import CS ipa-4.10.2-4.el9
This commit is contained in:
parent
ab0782cae8
commit
f898ed42f1
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1 @@
|
|||||||
SOURCES/freeipa-4.10.1.tar.gz
|
SOURCES/freeipa-4.10.2.tar.gz
|
||||||
|
@ -1 +1 @@
|
|||||||
6203cf7c2e003c35eb9ac40e4fd2954c6bea1856 SOURCES/freeipa-4.10.1.tar.gz
|
17d580b7dccb1586898aa46c7ecdd2bd2754ee5f SOURCES/freeipa-4.10.2.tar.gz
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
From 42be04fe4ff317efe599dcbc2637f94ecc6fa220 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
|
||||||
Date: Mon, 21 Nov 2022 16:12:46 +0200
|
|
||||||
Subject: [PATCH] updates: fix memberManager ACI to allow managers from a
|
|
||||||
specified group
|
|
||||||
|
|
||||||
The original implementation of the member manager added support for both
|
|
||||||
user and group managers but left out upgrade scenario. This means when
|
|
||||||
upgrading existing installation a manager whose rights defined by the
|
|
||||||
group membership would not be able to add group members until the ACI is
|
|
||||||
fixed.
|
|
||||||
|
|
||||||
Remove old ACI and add a full one during upgrade step.
|
|
||||||
|
|
||||||
Fixes: https://pagure.io/freeipa/issue/9286
|
|
||||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
|
||||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
---
|
|
||||||
install/updates/20-aci.update | 6 ++++--
|
|
||||||
1 file changed, 4 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/install/updates/20-aci.update b/install/updates/20-aci.update
|
|
||||||
index a168bb9573a9fbb9ff15f0b19bb8ec75b48d82a9..4a7ba137c4711aa3f8b064fdd482ffee76c59949 100644
|
|
||||||
--- a/install/updates/20-aci.update
|
|
||||||
+++ b/install/updates/20-aci.update
|
|
||||||
@@ -141,11 +141,13 @@ add:aci:(targetattr = "usercertificate")(version 3.0;acl "selfservice:Users can
|
|
||||||
|
|
||||||
# Allow member managers to modify members of user groups
|
|
||||||
dn: cn=groups,cn=accounts,$SUFFIX
|
|
||||||
-add:aci: (targetattr = "member")(targetfilter = "(objectclass=ipaUserGroup)")(version 3.0; acl "Allow member managers to modify members of user groups"; allow (write) userattr = "memberManager#USERDN";)
|
|
||||||
+remove:aci: (targetattr = "member")(targetfilter = "(objectclass=ipaUserGroup)")(version 3.0; acl "Allow member managers to modify members of user groups"; allow (write) userattr = "memberManager#USERDN";)
|
|
||||||
+add:aci: (targetattr = "member")(targetfilter = "(objectclass=ipaUserGroup)")(version 3.0; acl "Allow member managers to modify members of user groups"; allow (write) userattr = "memberManager#USERDN" or userattr = "memberManager#GROUPDN";)
|
|
||||||
|
|
||||||
# Allow member managers to modify members of host groups
|
|
||||||
dn: cn=hostgroups,cn=accounts,$SUFFIX
|
|
||||||
-add:aci: (targetattr = "member")(targetfilter = "(objectclass=ipaHostGroup)")(version 3.0; acl "Allow member managers to modify members of host groups"; allow (write) userattr = "memberManager#USERDN";)
|
|
||||||
+remove:aci: (targetattr = "member")(targetfilter = "(objectclass=ipaHostGroup)")(version 3.0; acl "Allow member managers to modify members of host groups"; allow (write) userattr = "memberManager#USERDN";)
|
|
||||||
+add:aci: (targetattr = "member")(targetfilter = "(objectclass=ipaHostGroup)")(version 3.0; acl "Allow member managers to modify members of host groups"; allow (write) userattr = "memberManager#USERDN" or userattr = "memberManager#GROUPDN";)
|
|
||||||
|
|
||||||
# Hosts can add and delete their own services
|
|
||||||
dn: cn=services,cn=accounts,$SUFFIX
|
|
||||||
--
|
|
||||||
2.38.1
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
|||||||
|
From 4f6ebb5fdf6d2514d4683247e5d1bfc6022a500e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
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 <flo@redhat.com>
|
||||||
|
Reviewed-By: Michal Polovka <mpolovka@redhat.com>
|
||||||
|
---
|
||||||
|
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
|
||||||
|
|
@ -1,42 +0,0 @@
|
|||||||
From 2d0a0cc40fb8674f30ba62980b1953cef840009e Mon Sep 17 00:00:00 2001
|
|
||||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
Date: Thu, 1 Dec 2022 13:58:58 +0100
|
|
||||||
Subject: [PATCH] Spec file: ipa-client depends on krb5-pkinit-openssl
|
|
||||||
|
|
||||||
Now that ipa-client-installs supports pkinit, the package
|
|
||||||
depends on krb5-pkinit-openssl.
|
|
||||||
Update the spec file, move the dependency from ipa-server
|
|
||||||
to ipa-client subpackage.
|
|
||||||
|
|
||||||
Fixes: https://pagure.io/freeipa/issue/9290
|
|
||||||
|
|
||||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
|
||||||
---
|
|
||||||
freeipa.spec.in | 3 ++-
|
|
||||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/freeipa.spec.in b/freeipa.spec.in
|
|
||||||
index f09741d7ad6c09e52c4bd24fcc9300584f83a49d..7dcf2e66abe40e6bde3491268b9c012f7578a8b6 100755
|
|
||||||
--- a/freeipa.spec.in
|
|
||||||
+++ b/freeipa.spec.in
|
|
||||||
@@ -449,7 +449,6 @@ Requires: nss-tools >= %{nss_version}
|
|
||||||
Requires(post): krb5-server >= %{krb5_version}
|
|
||||||
Requires(post): krb5-server >= %{krb5_base_version}
|
|
||||||
Requires: krb5-kdb-version = %{krb5_kdb_version}
|
|
||||||
-Requires: krb5-pkinit-openssl >= %{krb5_version}
|
|
||||||
Requires: cyrus-sasl-gssapi%{?_isa}
|
|
||||||
Requires: chrony
|
|
||||||
Requires: httpd >= %{httpd_version}
|
|
||||||
@@ -675,6 +674,8 @@ Requires: python3-sssdconfig >= %{sssd_version}
|
|
||||||
Requires: cyrus-sasl-gssapi%{?_isa}
|
|
||||||
Requires: chrony
|
|
||||||
Requires: krb5-workstation >= %{krb5_version}
|
|
||||||
+# support pkinit with client install
|
|
||||||
+Requires: krb5-pkinit-openssl >= %{krb5_version}
|
|
||||||
# authselect: sssd profile with-subid
|
|
||||||
%if 0%{?fedora} >= 36
|
|
||||||
Requires: authselect >= 1.4.0
|
|
||||||
--
|
|
||||||
2.38.1
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
|||||||
|
From 8d34f453fb139c4cef055a4963f307a760316a73 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Anuja More <amore@redhat.com>
|
||||||
|
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 <amore@redhat.com>
|
||||||
|
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
|
||||||
|
---
|
||||||
|
.../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
|
||||||
|
|
@ -0,0 +1,103 @@
|
|||||||
|
From 276138087158c6b2ea76b43c754084144e543c0b Mon Sep 17 00:00:00 2001
|
||||||
|
From: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
Date: Wed, 7 Jun 2023 11:32:21 -0400
|
||||||
|
Subject: [PATCH] Revert "Use the OpenSSL certificate parser in cert-find"
|
||||||
|
|
||||||
|
This reverts commit 191880bc9f77c3e8a3cecc82e6eea33ab5ad03e4.
|
||||||
|
|
||||||
|
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 <frenaud@redhat.com>
|
||||||
|
---
|
||||||
|
freeipa.spec.in | 2 --
|
||||||
|
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
|
||||||
|
--- a/freeipa.spec.in
|
||||||
|
+++ b/freeipa.spec.in
|
||||||
|
@@ -412,7 +412,6 @@ BuildRequires: python3-pylint
|
||||||
|
BuildRequires: python3-pytest-multihost
|
||||||
|
BuildRequires: python3-pytest-sourceorder
|
||||||
|
BuildRequires: python3-qrcode-core >= 5.0.0
|
||||||
|
-BuildRequires: python3-pyOpenSSL
|
||||||
|
BuildRequires: python3-samba
|
||||||
|
BuildRequires: python3-six
|
||||||
|
BuildRequires: python3-sss
|
||||||
|
@@ -884,7 +883,6 @@ Requires: python3-netifaces >= 0.10.4
|
||||||
|
Requires: python3-pyasn1 >= 0.3.2-2
|
||||||
|
Requires: python3-pyasn1-modules >= 0.3.2-2
|
||||||
|
Requires: python3-pyusb
|
||||||
|
-Requires: python3-pyOpenSSL
|
||||||
|
Requires: python3-qrcode-core >= 5.0.0
|
||||||
|
Requires: python3-requests
|
||||||
|
Requires: python3-six
|
||||||
|
diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py
|
||||||
|
index 400b1b3cec0aba82e699a4a981516e121f3e0c77..2e32f4ecd50ac92c28bcaffcebe9c2c87557858a 100644
|
||||||
|
--- a/ipaserver/plugins/cert.py
|
||||||
|
+++ b/ipaserver/plugins/cert.py
|
||||||
|
@@ -30,7 +30,6 @@ import cryptography.x509
|
||||||
|
from cryptography.hazmat.primitives import hashes, serialization
|
||||||
|
from dns import resolver, reversename
|
||||||
|
import six
|
||||||
|
-import sys
|
||||||
|
|
||||||
|
from ipalib import Command, Str, Int, Flag, StrEnum, SerialNumber
|
||||||
|
from ipalib import api
|
||||||
|
@@ -1618,19 +1617,7 @@ class cert_find(Search, CertMethod):
|
||||||
|
)
|
||||||
|
|
||||||
|
def _get_cert_key(self, cert):
|
||||||
|
- # for cert-find with a certificate value
|
||||||
|
- if isinstance(cert, x509.IPACertificate):
|
||||||
|
- return (DN(cert.issuer), cert.serial_number)
|
||||||
|
-
|
||||||
|
- issuer = []
|
||||||
|
- for oid, value in cert.get_issuer().get_components():
|
||||||
|
- issuer.append(
|
||||||
|
- '{}={}'.format(oid.decode('utf-8'), value.decode('utf-8'))
|
||||||
|
- )
|
||||||
|
- issuer = ','.join(issuer)
|
||||||
|
- # Use this to flip from OpenSSL reverse to X500 ordering
|
||||||
|
- issuer = DN(issuer).x500_text()
|
||||||
|
- return (DN(issuer), cert.get_serial_number())
|
||||||
|
+ return (DN(cert.issuer), cert.serial_number)
|
||||||
|
|
||||||
|
def _cert_search(self, pkey_only, **options):
|
||||||
|
result = collections.OrderedDict()
|
||||||
|
@@ -1750,11 +1737,6 @@ class cert_find(Search, CertMethod):
|
||||||
|
return result, False, complete
|
||||||
|
|
||||||
|
def _ldap_search(self, all, pkey_only, no_members, **options):
|
||||||
|
- # defer import of the OpenSSL module to not affect the requests
|
||||||
|
- # module which will use pyopenssl if this is available.
|
||||||
|
- if sys.modules.get('OpenSSL.SSL', False) is None:
|
||||||
|
- del sys.modules["OpenSSL.SSL"]
|
||||||
|
- import OpenSSL.crypto
|
||||||
|
ldap = self.api.Backend.ldap2
|
||||||
|
|
||||||
|
filters = []
|
||||||
|
@@ -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'):
|
||||||
|
- for der in entry.raw.get(attr, []):
|
||||||
|
- cert = OpenSSL.crypto.load_certificate(
|
||||||
|
- OpenSSL.crypto.FILETYPE_ASN1, der)
|
||||||
|
+ for cert in entry.get(attr, []):
|
||||||
|
cert_key = self._get_cert_key(cert)
|
||||||
|
try:
|
||||||
|
obj = result[cert_key]
|
||||||
|
except KeyError:
|
||||||
|
- obj = {'serial_number': cert.get_serial_number()}
|
||||||
|
+ obj = {'serial_number': cert.serial_number}
|
||||||
|
if not pkey_only and (all or not ca_enabled):
|
||||||
|
# Retrieving certificate details is now deferred
|
||||||
|
# until after all certificates are collected.
|
||||||
|
--
|
||||||
|
2.41.0
|
||||||
|
|
@ -1,54 +0,0 @@
|
|||||||
From 894dca12c120f0bfa705307a0609da47326b8fb2 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
Date: Thu, 12 Jan 2023 11:26:53 +0100
|
|
||||||
Subject: [PATCH] server install: remove error log about missing bkup file
|
|
||||||
|
|
||||||
The client installer code can be called in 3 different ways:
|
|
||||||
- from ipa-client-install CLI
|
|
||||||
- from ipa-replica-install CLI if the client is not already installed
|
|
||||||
- from ipa-server-install
|
|
||||||
|
|
||||||
In the last case, the client installer is called with
|
|
||||||
options.on_master=True
|
|
||||||
As a result, it's skipping the part that is creating the krb5
|
|
||||||
configuration:
|
|
||||||
if not options.on_master:
|
|
||||||
nolog = tuple()
|
|
||||||
configure_krb5_conf(...)
|
|
||||||
|
|
||||||
The configure_krb5_conf method is the place where the krb5.conf file is
|
|
||||||
backup'ed with the extention ".ipabkp". For a master installation, this
|
|
||||||
code is not called and the ipabkp file does not exist => delete raises
|
|
||||||
an error.
|
|
||||||
|
|
||||||
When delete fails because the file does not exist, no need to log an
|
|
||||||
error message.
|
|
||||||
|
|
||||||
Fixes: https://pagure.io/freeipa/issue/9306
|
|
||||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
---
|
|
||||||
ipaclient/install/client.py | 7 +++----
|
|
||||||
1 file changed, 3 insertions(+), 4 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py
|
|
||||||
index e5d3e8223efa1ebb69a1b7e963c394f9e1f38816..6e7f17d5b69581320866627cb5747a050cb6e32e 100644
|
|
||||||
--- a/ipaclient/install/client.py
|
|
||||||
+++ b/ipaclient/install/client.py
|
|
||||||
@@ -124,10 +124,9 @@ def cleanup(func):
|
|
||||||
os.rmdir(ccache_dir)
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
- try:
|
|
||||||
- os.remove(krb_name + ".ipabkp")
|
|
||||||
- except OSError:
|
|
||||||
- logger.error("Could not remove %s.ipabkp", krb_name)
|
|
||||||
+ # During master installation, the .ipabkp file is not created
|
|
||||||
+ # Ignore the delete error if it is "file does not exist"
|
|
||||||
+ remove_file(krb_name + ".ipabkp")
|
|
||||||
|
|
||||||
return inner
|
|
||||||
|
|
||||||
--
|
|
||||||
2.39.1
|
|
||||||
|
|
32
SOURCES/0004-Revert-cert_find-fix-call-with-all.patch
Normal file
32
SOURCES/0004-Revert-cert_find-fix-call-with-all.patch
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
From d83a4b0babdc7beb124d3748b5815ce309739eb7 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
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 <frenaud@redhat.com>
|
||||||
|
---
|
||||||
|
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
|
||||||
|
|
@ -1,118 +0,0 @@
|
|||||||
From 2520a7adff7a49ddcddaaf19f0e586425dc0d878 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Filip Dvorak <fdvorak@redhat.com>
|
|
||||||
Date: Tue, 6 Dec 2022 15:51:27 +0100
|
|
||||||
Subject: [PATCH] ipa tests: Add LANG before kinit command to fix issue with
|
|
||||||
locale settings
|
|
||||||
|
|
||||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
|
||||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
Reviewed-By: Michal Polovka <mpolovka@redhat.com>
|
|
||||||
---
|
|
||||||
ipatests/test_integration/test_krbtpolicy.py | 20 ++++++++++----------
|
|
||||||
1 file changed, 10 insertions(+), 10 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/ipatests/test_integration/test_krbtpolicy.py b/ipatests/test_integration/test_krbtpolicy.py
|
|
||||||
index eae16247bdfb195c1d91209cf2d11eac4c25018f..269cfb0a191821c229aaeb5a3eda0181c6e3ae62 100644
|
|
||||||
--- a/ipatests/test_integration/test_krbtpolicy.py
|
|
||||||
+++ b/ipatests/test_integration/test_krbtpolicy.py
|
|
||||||
@@ -23,7 +23,7 @@ PASSWORD = "Secret123"
|
|
||||||
USER1 = "testuser1"
|
|
||||||
USER2 = "testuser2"
|
|
||||||
MAXLIFE = 86400
|
|
||||||
-
|
|
||||||
+LANG_PKG = ["langpacks-en"]
|
|
||||||
|
|
||||||
def maxlife_within_policy(input, maxlife, slush=3600):
|
|
||||||
"""Given klist output of the TGT verify that it is within policy
|
|
||||||
@@ -45,7 +45,6 @@ def maxlife_within_policy(input, maxlife, slush=3600):
|
|
||||||
|
|
||||||
return maxlife >= diff >= maxlife - slush
|
|
||||||
|
|
||||||
-
|
|
||||||
@pytest.fixture
|
|
||||||
def reset_to_default_policy():
|
|
||||||
"""Reset default user authentication and user authentication type"""
|
|
||||||
@@ -70,7 +69,7 @@ def reset_to_default_policy():
|
|
||||||
def kinit_check_life(master, user):
|
|
||||||
"""Acquire a TGT and check if it's within the lifetime window"""
|
|
||||||
master.run_command(["kinit", user], stdin_text=f"{PASSWORD}\n")
|
|
||||||
- result = master.run_command("klist | grep krbtgt")
|
|
||||||
+ result = master.run_command("LANG=en_US.utf-8 klist | grep krbtgt")
|
|
||||||
assert maxlife_within_policy(result.stdout_text, MAXLIFE) is True
|
|
||||||
|
|
||||||
|
|
||||||
@@ -81,6 +80,7 @@ class TestPWPolicy(IntegrationTest):
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def install(cls, mh):
|
|
||||||
+ tasks.install_packages(cls.master, LANG_PKG)
|
|
||||||
tasks.install_master(cls.master)
|
|
||||||
tasks.create_active_user(cls.master, USER1, PASSWORD)
|
|
||||||
tasks.create_active_user(cls.master, USER2, PASSWORD)
|
|
||||||
@@ -100,7 +100,7 @@ class TestPWPolicy(IntegrationTest):
|
|
||||||
|
|
||||||
master.run_command(['kinit', USER1],
|
|
||||||
stdin_text=PASSWORD + '\n')
|
|
||||||
- result = master.run_command('klist | grep krbtgt')
|
|
||||||
+ result = master.run_command("LANG=en_US.utf-8 klist | grep krbtgt")
|
|
||||||
assert maxlife_within_policy(result.stdout_text, MAXLIFE) is True
|
|
||||||
|
|
||||||
def test_krbtpolicy_password_and_hardended(self):
|
|
||||||
@@ -122,7 +122,7 @@ class TestPWPolicy(IntegrationTest):
|
|
||||||
|
|
||||||
master.run_command(['kinit', USER1],
|
|
||||||
stdin_text=PASSWORD + '\n')
|
|
||||||
- result = master.run_command('klist | grep krbtgt')
|
|
||||||
+ result = master.run_command('LANG=en_US.utf-8 klist | grep krbtgt')
|
|
||||||
assert maxlife_within_policy(result.stdout_text, 600,
|
|
||||||
slush=600) is True
|
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ class TestPWPolicy(IntegrationTest):
|
|
||||||
# Verify that the short policy only applies to USER1
|
|
||||||
master.run_command(['kinit', USER2],
|
|
||||||
stdin_text=PASSWORD + '\n')
|
|
||||||
- result = master.run_command('klist | grep krbtgt')
|
|
||||||
+ result = master.run_command('LANG=en_US.utf-8 klist | grep krbtgt')
|
|
||||||
assert maxlife_within_policy(result.stdout_text, MAXLIFE) is True
|
|
||||||
|
|
||||||
def test_krbtpolicy_hardended(self):
|
|
||||||
@@ -151,7 +151,7 @@ class TestPWPolicy(IntegrationTest):
|
|
||||||
|
|
||||||
master.run_command(['kinit', USER1],
|
|
||||||
stdin_text=PASSWORD + '\n')
|
|
||||||
- result = master.run_command('klist | grep krbtgt')
|
|
||||||
+ result = master.run_command('LANG=en_US.utf-8 klist | grep krbtgt')
|
|
||||||
assert maxlife_within_policy(result.stdout_text, 1800,
|
|
||||||
slush=1800) is True
|
|
||||||
|
|
||||||
@@ -160,7 +160,7 @@ class TestPWPolicy(IntegrationTest):
|
|
||||||
# Verify that the short policy only applies to USER1
|
|
||||||
master.run_command(['kinit', USER2],
|
|
||||||
stdin_text=PASSWORD + '\n')
|
|
||||||
- result = master.run_command('klist | grep krbtgt')
|
|
||||||
+ result = master.run_command('LANG=en_US.utf-8 klist | grep krbtgt')
|
|
||||||
assert maxlife_within_policy(result.stdout_text, MAXLIFE) is True
|
|
||||||
|
|
||||||
def test_krbtpolicy_password(self):
|
|
||||||
@@ -173,7 +173,7 @@ class TestPWPolicy(IntegrationTest):
|
|
||||||
|
|
||||||
master.run_command(['kinit', USER2],
|
|
||||||
stdin_text=PASSWORD + '\n')
|
|
||||||
- result = master.run_command('klist | grep krbtgt')
|
|
||||||
+ result = master.run_command('LANG=en_US.utf-8 klist | grep krbtgt')
|
|
||||||
assert maxlife_within_policy(result.stdout_text, 1200,
|
|
||||||
slush=1200) is True
|
|
||||||
|
|
||||||
@@ -183,7 +183,7 @@ class TestPWPolicy(IntegrationTest):
|
|
||||||
master.run_command(['ipa', 'krbtpolicy-reset', USER2])
|
|
||||||
master.run_command(['kinit', USER2],
|
|
||||||
stdin_text=PASSWORD + '\n')
|
|
||||||
- result = master.run_command('klist | grep krbtgt')
|
|
||||||
+ result = master.run_command('LANG=en_US.utf-8 klist | grep krbtgt')
|
|
||||||
assert maxlife_within_policy(result.stdout_text, MAXLIFE) is True
|
|
||||||
|
|
||||||
def test_krbtpolicy_otp(self, reset_to_default_policy):
|
|
||||||
--
|
|
||||||
2.39.1
|
|
||||||
|
|
@ -0,0 +1,115 @@
|
|||||||
|
From d9aa75459d650e5282a160a3eef09ed175dc5b51 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
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 <rcritten@redhat.com>
|
||||||
|
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
|
||||||
|
---
|
||||||
|
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
|
||||||
|
|
@ -1,48 +0,0 @@
|
|||||||
From 97fc368df2db3b559a9def236d3c3e0a12bcdd0a Mon Sep 17 00:00:00 2001
|
|
||||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
Date: Mon, 23 Jan 2023 20:28:17 +0100
|
|
||||||
Subject: [PATCH] trust-add: handle missing msSFU30MaxGidNumber
|
|
||||||
|
|
||||||
When ipa trust-add is executed with --range-type ad-trust-posix,
|
|
||||||
the server tries to find the max uidnumber and max gidnumber
|
|
||||||
from AD domain controller.
|
|
||||||
The values are extracted from the entry
|
|
||||||
CN=<domain>,CN=ypservers,CN=ypServ30,CN=RpcServices,CN=System,<AD suffix>
|
|
||||||
in the msSFU30MaxUidNumber and msSFU30MaxGidNumber attributes.
|
|
||||||
|
|
||||||
msSFU30MaxUidNumber is required but not msSFU30MaxGidNumber.
|
|
||||||
In case msSFU30MaxGidNumber is missing, the code is currently assigning
|
|
||||||
a "None" value and later on evaluates the max between this value and
|
|
||||||
msSFU30MaxUidNumber. The max function cannot compare None and a list
|
|
||||||
of string and triggers an exception.
|
|
||||||
|
|
||||||
To avoid the exception, assign [b'0'] to max gid if msSFU30MaxGidNumber
|
|
||||||
is missing. This way, the comparison succeeds and max returns the
|
|
||||||
value from msSFU30MaxUidNumber.
|
|
||||||
|
|
||||||
Fixes: https://pagure.io/freeipa/issue/9310
|
|
||||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
---
|
|
||||||
ipaserver/plugins/trust.py | 5 ++++-
|
|
||||||
1 file changed, 4 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/ipaserver/plugins/trust.py b/ipaserver/plugins/trust.py
|
|
||||||
index c074f6d6e609476e416c95bcbe607654718ae9ce..79264b8d8a3b15dd4e5d0553e4ce42194b0ae044 100644
|
|
||||||
--- a/ipaserver/plugins/trust.py
|
|
||||||
+++ b/ipaserver/plugins/trust.py
|
|
||||||
@@ -379,7 +379,10 @@ def add_range(myapi, trustinstance, range_name, dom_sid, *keys, **options):
|
|
||||||
range_type = u'ipa-ad-trust-posix'
|
|
||||||
|
|
||||||
max_uid = info.get('msSFU30MaxUidNumber')
|
|
||||||
- max_gid = info.get('msSFU30MaxGidNumber', None)
|
|
||||||
+ # if max_gid is missing, assume 0 and the max will
|
|
||||||
+ # be obtained from max_uid. We just checked that
|
|
||||||
+ # msSFU30MaxUidNumber is defined
|
|
||||||
+ max_gid = info.get('msSFU30MaxGidNumber', [b'0'])
|
|
||||||
max_id = int(max(max_uid, max_gid)[0])
|
|
||||||
|
|
||||||
base_id = int(info.get('msSFU30OrderNumber')[0])
|
|
||||||
--
|
|
||||||
2.39.1
|
|
||||||
|
|
38
SOURCES/0006-Upgrade-add-PKI-drop-in-file-if-missing.patch
Normal file
38
SOURCES/0006-Upgrade-add-PKI-drop-in-file-if-missing.patch
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
From f25003a730c0e28c22fae5fce607df734b55525c Mon Sep 17 00:00:00 2001
|
||||||
|
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
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 <flo@redhat.com>
|
||||||
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
---
|
||||||
|
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
|
||||||
|
|
@ -1,337 +0,0 @@
|
|||||||
From 51b1c22d025bf40e9ef488bb0faf0c8dff303ccd Mon Sep 17 00:00:00 2001
|
|
||||||
From: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
Date: Thu, 8 Dec 2022 16:18:07 -0500
|
|
||||||
Subject: [PATCH] doc: Design for certificate pruning
|
|
||||||
|
|
||||||
This describes how the certificate pruning capability of PKI
|
|
||||||
introduced in v11.3.0 will be integrated into IPA, primarily for
|
|
||||||
ACME.
|
|
||||||
|
|
||||||
Related: https://pagure.io/freeipa/issue/9294
|
|
||||||
|
|
||||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
|
|
||||||
---
|
|
||||||
doc/designs/expired_certificate_pruning.md | 297 +++++++++++++++++++++
|
|
||||||
doc/designs/index.rst | 1 +
|
|
||||||
2 files changed, 298 insertions(+)
|
|
||||||
create mode 100644 doc/designs/expired_certificate_pruning.md
|
|
||||||
|
|
||||||
diff --git a/doc/designs/expired_certificate_pruning.md b/doc/designs/expired_certificate_pruning.md
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..2c10d914020d3c12b6abb028323cd6796ec33e00
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/doc/designs/expired_certificate_pruning.md
|
|
||||||
@@ -0,0 +1,297 @@
|
|
||||||
+# Expired Certificate Pruning
|
|
||||||
+
|
|
||||||
+## Overview
|
|
||||||
+
|
|
||||||
+https://pagure.io/dogtagpki/issue/1750
|
|
||||||
+
|
|
||||||
+When using short-lived certs and regular issuance, the expired certs can build up in the PKI database and cause issues with replication, performance and overall database size.
|
|
||||||
+
|
|
||||||
+PKI has provided a new feature in 11.3.0, pruning, which is a job that can be executed on a schedule or manually to remove expired certificates and requests.
|
|
||||||
+
|
|
||||||
+Random Serial Numbers v3 (RSNv3) is mandatory to enable pruning.
|
|
||||||
+
|
|
||||||
+Both pruning and RSNv3 require PKI 11.3.0 or higher.
|
|
||||||
+
|
|
||||||
+## Use Cases
|
|
||||||
+
|
|
||||||
+ACME certificates in particular are generally short-lived and expired certificates can build up quickly in a dynamic environment. An example is a CI system that requests one or more certificates per run. These will build up infinitely without a way to remove the expired certificates.
|
|
||||||
+
|
|
||||||
+Another case is simply a very long-lived installation. Over time as hosts come and go certificates build up.
|
|
||||||
+
|
|
||||||
+## How to Use
|
|
||||||
+
|
|
||||||
+https://github.com/dogtagpki/pki/wiki/Configuring-CA-Database-Pruning provides a thorough description of the capabilities of the pruning job.
|
|
||||||
+
|
|
||||||
+The default configuration is to remove expired certificates and incomplete requests after 30 days.
|
|
||||||
+
|
|
||||||
+Pruning is disabled by default.
|
|
||||||
+
|
|
||||||
+Configuration is a four-step process:
|
|
||||||
+
|
|
||||||
+1. Configure the expiration thresholds
|
|
||||||
+2. Enable the job
|
|
||||||
+3. Schedule the job
|
|
||||||
+4. Restart the CA
|
|
||||||
+
|
|
||||||
+The job will be scheduled to use the PKI built-in cron-like timer. It is configured nearly identically to `crontab(5)`. On execution it will remove certificates and requests that fall outside the configured thresholds. LDAP search/time limits can be used to control how many are removed at once.
|
|
||||||
+
|
|
||||||
+In addition to the automated schedule it is possible to manually run the pruning job.
|
|
||||||
+
|
|
||||||
+The tool will not restart the CA. It will be left as an exercise for the user, who will be notified as needed.
|
|
||||||
+
|
|
||||||
+### Where to use
|
|
||||||
+
|
|
||||||
+The pruning configuration is not replicated. It should not be necessary to enable this task on all IPA servers, or more than one.
|
|
||||||
+
|
|
||||||
+Running the task simultaneously on multiple servers has a few downsides:
|
|
||||||
+
|
|
||||||
+* Additional stress on the LDAP server searching for expired certificates and requests
|
|
||||||
+* Unnecessary replication load deleting the same entries on multiple servers
|
|
||||||
+
|
|
||||||
+While enabling this on a single server represents a single-point-of-failure there should be no catastrophic consequences other than expired certificates and requests potentially building up. This can be cleared by enabling pruning on a different server. Depending on the size of the backlog this could take a couple of executions to catch up.
|
|
||||||
+
|
|
||||||
+## Design
|
|
||||||
+
|
|
||||||
+There are several operations, most of which act locally and one of which uses the PKI REST API.
|
|
||||||
+
|
|
||||||
+1. Updating the job configuration (enable, thresholds, etc). This will be done by running the `pki-server ca-config-set` command which modifies CS.cfg directly per the PKI wiki. A restart is required.
|
|
||||||
+
|
|
||||||
+2. Retrieving the current configuration for display. The `pki-server ca-config-find` command returns the entire configuration so the results will need to be filtered.
|
|
||||||
+
|
|
||||||
+3. Managing the job. This can be done using the REST API, https://github.com/dogtagpki/pki/wiki/PKI-REST-API . Operations include enabling the job and triggering it to run now.
|
|
||||||
+
|
|
||||||
+Theoretically for operations 1 and 2 we could use existing code to manually update `CS.cfg` and retrieve values. For future-proofing purposes calling `pki-server` is probably the better long-term option given the limited number of times this will be used. Configuration is likely to be one and done.
|
|
||||||
+
|
|
||||||
+There are four values each that can be managed for pruning certificates and requests:
|
|
||||||
+
|
|
||||||
+* expired cert/incomplete request time
|
|
||||||
+* time unit
|
|
||||||
+* LDAP search size limit
|
|
||||||
+* LDAP search time limit
|
|
||||||
+
|
|
||||||
+The first two configure when an expired certificate or incomplete request will be deleted. The unit can be one of: minute, hour, day, year. By default it is 30 days.
|
|
||||||
+
|
|
||||||
+The LDAP limits control how many entries are returned and how long the search can take. By default it is 1000 entries and unlimited time.
|
|
||||||
+
|
|
||||||
+### Configuration settings
|
|
||||||
+
|
|
||||||
+The configuration values will be set by running `pki-server ca-config-set` This will ensure best forward compatibility. The options are case-sensitive and not validated by the CA until restart. The values are not applied until the CA is restarted.
|
|
||||||
+
|
|
||||||
+### Configuring job execution time
|
|
||||||
+
|
|
||||||
+The CA provides a cron-like interface for scheduling jobs. To configure the job to run at midnight on the first of every month the PKI equivalent command-line is:
|
|
||||||
+
|
|
||||||
+```
|
|
||||||
+pki-server ca-config-set jobsScheduler.job.pruning.cron `"0 0 1 * *"`
|
|
||||||
+```
|
|
||||||
+
|
|
||||||
+This will be the default when pruning is enabled. A separate configuration option will be available for fine-tuning execution time.
|
|
||||||
+
|
|
||||||
+The format is defined https://access.redhat.com/documentation/en-us/red_hat_certificate_system/9/html/administration_guide/setting_up_specific_jobs#Frequency_Settings_for_Automated_Jobs
|
|
||||||
+
|
|
||||||
+### REST Authentication and Authorization
|
|
||||||
+
|
|
||||||
+The REST API for pruning is documented at https://github.com/dogtagpki/pki/wiki/PKI-Start-Job-REST-API
|
|
||||||
+
|
|
||||||
+A PKI job can define an owner that can manage the job over the REST API. We will automatically define the owner as `ipara` when pruning is enabled.
|
|
||||||
+
|
|
||||||
+Manually running the job will be done using the PKI REST API. Authentication to this API for our purposes is done at the `/ca/rest/account/login` endpoint. A cookie is returned which will be used in any subsequent calls. The IPA RA agent certificate will be used for authentication and authorization.
|
|
||||||
+
|
|
||||||
+### Commands
|
|
||||||
+
|
|
||||||
+This will be implemented in the ipa-acme-manage command. While strictly not completely ACME-related this is the primary driver for pruning.
|
|
||||||
+
|
|
||||||
+A new verb will be added, pruning, to be used for enabling and configuring pruning.
|
|
||||||
+
|
|
||||||
+### Enabling pruning
|
|
||||||
+
|
|
||||||
+`# ipa-acme-manage pruning --enable=TRUE`
|
|
||||||
+
|
|
||||||
+Enabling the job will call
|
|
||||||
+
|
|
||||||
+`# pki-server ca-config-set jobsScheduler.job.pruning.enabled true`
|
|
||||||
+
|
|
||||||
+This will also set jobsScheduler.job.pruning.cron to `"0 0 1 * *"` if it has not already been set.
|
|
||||||
+
|
|
||||||
+Additionally it will set the job owner to `ipara` with:
|
|
||||||
+
|
|
||||||
+`# pki-server ca-config-set jobsScheduler.job.pruning.owner ipara`
|
|
||||||
+
|
|
||||||
+Disabling the job will call
|
|
||||||
+
|
|
||||||
+`# pki-server ca-config-unset jobsScheduler.job.pruning.enabled`
|
|
||||||
+
|
|
||||||
+### Cron settings
|
|
||||||
+
|
|
||||||
+To modify the cron settings:
|
|
||||||
+
|
|
||||||
+`# ipa-acme-manage pruning --cron="Minute Hour Day_of_month Month_of_year Day_of_week"`
|
|
||||||
+
|
|
||||||
+Validation of the value will be:
|
|
||||||
+* each of the options is an integer
|
|
||||||
+* minute is within 0-59
|
|
||||||
+* hour is within 0-23
|
|
||||||
+* day of month is within 0-31
|
|
||||||
+* month of year is within 1-12
|
|
||||||
+* day of week is within 0-6
|
|
||||||
+
|
|
||||||
+No validation of setting February 31st will be done. That will be left to PKI. Buyer beware.
|
|
||||||
+
|
|
||||||
+### Disabling pruning
|
|
||||||
+
|
|
||||||
+`$ ipa-acme-manage pruning --enable=FALSE`
|
|
||||||
+
|
|
||||||
+This will remove the configuration option for `jobsScheduler.job.pruning.cron` just to be sure it no longer runs.
|
|
||||||
+
|
|
||||||
+### Configuration
|
|
||||||
+
|
|
||||||
+#### Pruning certificates
|
|
||||||
+
|
|
||||||
+`$ ipa-acme-manage pruning --certretention=VALUE --certretentionunit=UNIT`
|
|
||||||
+
|
|
||||||
+will be the equivalent of:
|
|
||||||
+
|
|
||||||
+`$ pki-server ca-config-set jobsScheduler.job.pruning.certRetentionTime 30`
|
|
||||||
+
|
|
||||||
+`$ pki-server ca-config-set jobsScheduler.job.pruning.certRetentionUnit day`
|
|
||||||
+
|
|
||||||
+The unit will always be required when modifying the time.
|
|
||||||
+
|
|
||||||
+`$ ipa-acme-manage pruning --certsearchsizelimit=VALUE --certsearchtimelimit=VALUE`
|
|
||||||
+
|
|
||||||
+will be the equivalent of:
|
|
||||||
+
|
|
||||||
+`$ pki-server ca-config-set jobsScheduler.job.pruning.certSearchSizeLimit 1000`
|
|
||||||
+
|
|
||||||
+`$ pki-server ca-config-set jobsScheduler.job.pruning.certSearchTimeLimit 0`
|
|
||||||
+
|
|
||||||
+A value of 0 for searchtimelimit is unlimited.
|
|
||||||
+
|
|
||||||
+#### Pruning requests
|
|
||||||
+
|
|
||||||
+`$ ipa-acme-manage pruning --requestretention=VALUE --requestretentionunit=UNIT`
|
|
||||||
+
|
|
||||||
+will be the equivalent of:
|
|
||||||
+
|
|
||||||
+`$ pki-server ca-config-set jobsScheduler.job.pruning.requestRetentionTime 30`
|
|
||||||
+
|
|
||||||
+`$ pki-server ca-config-set jobsScheduler.job.pruning.requestRetentionUnit day`
|
|
||||||
+
|
|
||||||
+The unit will always be required when modifying the time.
|
|
||||||
+
|
|
||||||
+`$ ipa-acme-manage pruning --requestsearchsizelimit=VALUE --requestsearchtimelimit=VALUE`
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+will be the equivalent of:
|
|
||||||
+
|
|
||||||
+`$ pki-server ca-config-set jobsScheduler.job.pruning.requestSearchSizeLimit 1000`
|
|
||||||
+
|
|
||||||
+`$ pki-server ca-config-set jobsScheduler.job.pruning.requestSearchTimeLimit 0`
|
|
||||||
+
|
|
||||||
+A value of 0 for searchtimelimit is unlimited.
|
|
||||||
+
|
|
||||||
+These options set the client-side limits. The server imposes its own search size and look through limits. This can be tuned for the uid=pkidbuser,ou=people,o=ipaca user via https://access.redhat.com/documentation/en-us/red_hat_directory_server/11/html/administration_guide/ldapsearch-ex-complex-range
|
|
||||||
+
|
|
||||||
+### Showing the Configuration
|
|
||||||
+
|
|
||||||
+To display the current configuration run `pki-server ca-config-find` and filter the results to only those that contain `jobsScheduler.job.pruning`.
|
|
||||||
+
|
|
||||||
+Default values are not included so will need to be set by `ipa-acme-manage` before displaying.
|
|
||||||
+
|
|
||||||
+Output may look something like:
|
|
||||||
+
|
|
||||||
+```console
|
|
||||||
+# ipa-acme-manage pruning --config-show
|
|
||||||
+Enabled: TRUE
|
|
||||||
+Certificate retention time: 30 days
|
|
||||||
+Certificate search size limit: 1000
|
|
||||||
+Certificate search time limit: 0
|
|
||||||
+Request retention time: 30 days
|
|
||||||
+Request search size limit: 1000
|
|
||||||
+Request search time limit: 0
|
|
||||||
+Cron: 0 0 1 * *
|
|
||||||
+```
|
|
||||||
+
|
|
||||||
+## Implementation
|
|
||||||
+
|
|
||||||
+For online REST operations (login, run job) we will use the `ipaserver/plugins/dogtag.py::RestClient` class to manage the requests. This will take care of the authentication cookie, etc.
|
|
||||||
+
|
|
||||||
+The class uses dogtag.https_request() will can take PEM cert and key files as arguments. These will be used for authentication.
|
|
||||||
+
|
|
||||||
+For the non-REST operations (configuration, cron settings) the tool will fork out to pki-server ca-config-set.
|
|
||||||
+
|
|
||||||
+### UI
|
|
||||||
+
|
|
||||||
+This will only be configurable on the command-line.
|
|
||||||
+
|
|
||||||
+### CLI
|
|
||||||
+
|
|
||||||
+Overview of the CLI commands. Example:
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+| Command | Options |
|
|
||||||
+| --- | ----- |
|
|
||||||
+| ipa-acme-manage pruning | --enable=TRUE |
|
|
||||||
+| ipa-acme-manage pruning | --enable=FALSE |
|
|
||||||
+| ipa-acme-manage pruning | --cron=`"0 0 1 * *"` |
|
|
||||||
+| ipa-acme-manage pruning | --certretention=30 --certretentionunit=day |
|
|
||||||
+| ipa-acme-manage pruning | --certsearchsizelimit=1000 --certsearchtimelimit=0 |
|
|
||||||
+| ipa-acme-manage pruning | --requestretention=30 --requestretentionunit=day |
|
|
||||||
+| ipa-acme-manage pruning | --requestsearchsizelimit=1000 --requestsearchtimelimit=0 |
|
|
||||||
+| ipa-acme-manage pruning | --config-show |
|
|
||||||
+
|
|
||||||
+ipa-acme-manage can only be run as root.
|
|
||||||
+
|
|
||||||
+### Configuration
|
|
||||||
+
|
|
||||||
+Configuration changes will be made to /etc/pki/pki-tomcat/ca/CS.cfg
|
|
||||||
+
|
|
||||||
+## Upgrade
|
|
||||||
+
|
|
||||||
+No expected impact on upgrades.
|
|
||||||
+
|
|
||||||
+## Test plan
|
|
||||||
+
|
|
||||||
+Testing will consist of:
|
|
||||||
+
|
|
||||||
+* Use the default configuration
|
|
||||||
+* enabling the pruning job
|
|
||||||
+* issue one or more certificates
|
|
||||||
+* move time forward +1 days after expiration
|
|
||||||
+* manually running the job
|
|
||||||
+* validating that the certificates are removed
|
|
||||||
+
|
|
||||||
+For size/time limit testing, create a large number of certificates/requests and set the search limit to a low value, then ensure that the number of deleted certs is equal to the search limit. Testing timelimit in this way may be less predictable as it may require a massive number of entries to find to timeout on a non-busy server.
|
|
||||||
+
|
|
||||||
+## Troubleshooting and debugging
|
|
||||||
+
|
|
||||||
+The PKI debug log will contain job information.
|
|
||||||
+
|
|
||||||
+```
|
|
||||||
+2022-12-08 21:14:25 [https-jsse-nio-8443-exec-8] INFO: JobService: Starting job pruning
|
|
||||||
+2022-12-08 21:14:25 [https-jsse-nio-8443-exec-8] INFO: JobService: - principal: null
|
|
||||||
+2022-12-08 21:14:51 [https-jsse-nio-8443-exec-10] INFO: JobService: Starting job pruning 2022-12-08 21:14:51 [https-jsse-nio-8443-exec-10] INFO: JobService: - principal: null
|
|
||||||
+2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: PKIRealm: Authenticating certificate chain:
|
|
||||||
+2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: PKIRealm: - CN=IPA RA,O=EXAMPLE.TEST
|
|
||||||
+2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: PKIRealm: - CN=Certificate Authority,O=EXAMPLE.TEST
|
|
||||||
+2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: LDAPSession: Retrieving cn=19072098145751813471503860299601579276,ou=certificateRepository, ou=ca,o=ipaca
|
|
||||||
+2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: CertUserDBAuthentication: UID ipara authenticated.
|
|
||||||
+2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: PKIRealm: User ipara authenticated
|
|
||||||
+2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: UGSubsystem: Retrieving user uid=ipara,ou=People,o=ipaca
|
|
||||||
+2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: PKIRealm: User DN: uid=ipara,ou=people,o=ipaca
|
|
||||||
+2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: PKIRealm: Roles:
|
|
||||||
+2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: PKIRealm: - Certificate Manager Agents
|
|
||||||
+2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: PKIRealm: - Registration Manager Agents
|
|
||||||
+2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: PKIRealm: - Security Domain Administrators
|
|
||||||
+2022-12-08 21:15:11 [https-jsse-nio-8443-exec-11] INFO: PKIRealm: - Enterprise ACME Administrators
|
|
||||||
+2022-12-08 21:15:24 [https-jsse-nio-8443-exec-12] INFO: JobService: Starting job pruning
|
|
||||||
+2022-12-08 21:15:24 [https-jsse-nio-8443-exec-12] INFO: JobService: - principal: GenericPrincipal[ipara(Certificate Manager Agents,Enterprise ACME Administrators,Registration Manager Agents,Security Domain Administrators,)]
|
|
||||||
+2022-12-08 21:15:24 [https-jsse-nio-8443-exec-12] INFO: JobsScheduler: Starting job pruning
|
|
||||||
+2022-12-08 21:15:24 [pruning] INFO: PruningJob: Running pruning job at Thu Dec 08 21:15:24 UTC 2022
|
|
||||||
+2022-12-08 21:15:24 [pruning] INFO: PruningJob: Pruning certs expired before Tue Nov 08 21:15:24 UTC 2022
|
|
||||||
+2022-12-08 21:15:24 [pruning] INFO: PruningJob: - filter: (&(x509Cert.notAfter<=1667942124527)(!(x509Cert.notAfter=1667942124527)))
|
|
||||||
+2022-12-08 21:15:24 [pruning] INFO: LDAPSession: Searching ou=certificateRepository, ou=ca,o=ipaca for (&(notAfter<=20221108211524Z)(!(notAfter=20221108211524Z)))
|
|
||||||
+2022-12-08 21:15:24 [pruning] INFO: PruningJob: Pruning incomplete requests last modified before Tue Nov 08 21:15:24 UTC 2022
|
|
||||||
+2022-12-08 21:15:24 [pruning] INFO: PruningJob: - filter: (&(!(requestState=complete))(requestModifyTime<=1667942124527)(!(requestModifyTime=1667942124527)))
|
|
||||||
+2022-12-08 21:15:24 [pruning] INFO: LDAPSession: Searching ou=ca, ou=requests,o=ipaca for (&(!(requestState=complete))(dateOfModify<=20221108211524Z)(!(dateOfModify=20221108211524Z)))
|
|
||||||
+```
|
|
||||||
diff --git a/doc/designs/index.rst b/doc/designs/index.rst
|
|
||||||
index 570e526fe35d510feeac62a44dd59224289e0506..1d41c0f84f0d7d3d5f184a47e31b4e71a890805d 100644
|
|
||||||
--- a/doc/designs/index.rst
|
|
||||||
+++ b/doc/designs/index.rst
|
|
||||||
@@ -14,6 +14,7 @@ FreeIPA design documentation
|
|
||||||
hsm.md
|
|
||||||
krb-ticket-policy.md
|
|
||||||
extdom-plugin-protocol.md
|
|
||||||
+ expired_certificate_pruning.md
|
|
||||||
expiring-password-notification.md
|
|
||||||
ldap_grace_period.md
|
|
||||||
ldap_pam_passthrough.md
|
|
||||||
--
|
|
||||||
2.39.1
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
|||||||
|
From 392e60e3fa0e39a2e364268a21d869a2f3a85905 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
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 <flo@redhat.com>
|
||||||
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
---
|
||||||
|
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
|
||||||
|
|
@ -1,684 +0,0 @@
|
|||||||
From 9246a8a003b2b0062e07c289cd7cde8fe902b16f Mon Sep 17 00:00:00 2001
|
|
||||||
From: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
Date: Thu, 12 Jan 2023 15:06:27 -0500
|
|
||||||
Subject: [PATCH] ipa-acme-manage: add certificate/request pruning management
|
|
||||||
|
|
||||||
Configures PKI to remove expired certificates and non-resolved
|
|
||||||
requests on a schedule.
|
|
||||||
|
|
||||||
This is geared towards ACME which can generate a lot of certificates
|
|
||||||
over a short period of time but is general purpose. It lives in
|
|
||||||
ipa-acme-manage because that is the primary reason for including it.
|
|
||||||
|
|
||||||
Random Serial Numbers v3 must be enabled for this to work.
|
|
||||||
|
|
||||||
Enabling pruning enables the job scheduler within CS and sets the
|
|
||||||
job user as the IPA RA user which has full rights to certificates
|
|
||||||
and requests.
|
|
||||||
|
|
||||||
Disabling pruning does not disable the job scheduler because the
|
|
||||||
tool is stateless. Having the scheduler enabled should not be a
|
|
||||||
problem.
|
|
||||||
|
|
||||||
A restart of PKI is required to apply any changes. This tool forks
|
|
||||||
out to pki-server which does direct writes to CS.cfg. It might
|
|
||||||
be easier to use our own tooling for this but this makes the
|
|
||||||
integration tighter so we pick up any improvements in PKI.
|
|
||||||
|
|
||||||
The "cron" setting is quite limited, taking only integer values
|
|
||||||
and *. It does not accept ranges, either - or /.
|
|
||||||
|
|
||||||
No error checking is done in PKI when setting a value, only when
|
|
||||||
attempting to use it, so some rudimentary validation is done.
|
|
||||||
|
|
||||||
Fixes: https://pagure.io/freeipa/issue/9294
|
|
||||||
|
|
||||||
Signed-off-by: Rob Crittenden rcritten@redhat.com
|
|
||||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
---
|
|
||||||
install/tools/man/ipa-acme-manage.1 | 83 +++++++
|
|
||||||
ipaserver/install/ipa_acme_manage.py | 303 ++++++++++++++++++++++++-
|
|
||||||
ipatests/test_integration/test_acme.py | 158 +++++++++++++
|
|
||||||
3 files changed, 534 insertions(+), 10 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/install/tools/man/ipa-acme-manage.1 b/install/tools/man/ipa-acme-manage.1
|
|
||||||
index e15d25bd0017d8bd71e425fcb633827fa6f67693..e6cec4e4a7fd460c514a72456a2dc9a2e3682ebd 100644
|
|
||||||
--- a/install/tools/man/ipa-acme-manage.1
|
|
||||||
+++ b/install/tools/man/ipa-acme-manage.1
|
|
||||||
@@ -27,6 +27,89 @@ Disable the ACME service on this host.
|
|
||||||
.TP
|
|
||||||
\fBstatus\fR
|
|
||||||
Display the status of the ACME service.
|
|
||||||
+.TP
|
|
||||||
+\fBpruning\fR
|
|
||||||
+Configure certificate and request pruning.
|
|
||||||
+
|
|
||||||
+.SH "PRUNING"
|
|
||||||
+Pruning is a job that runs in the CA that can remove expired
|
|
||||||
+certificates and certificate requests which have not been issued.
|
|
||||||
+This is particularly important when using short-lived certificates
|
|
||||||
+like those issued with the ACME protocol. Pruning requires that
|
|
||||||
+the IPA server be installed with random serial numbers enabled.
|
|
||||||
+
|
|
||||||
+The CA needs to be restarted after modifying the pruning configuration.
|
|
||||||
+
|
|
||||||
+The job is a cron-like task within the CA that is controlled by a
|
|
||||||
+number of options which dictate how long after the certificate or
|
|
||||||
+request is considered no longer valid and removed from the LDAP
|
|
||||||
+database.
|
|
||||||
+
|
|
||||||
+The cron time and date fields are:
|
|
||||||
+.IP
|
|
||||||
+.ta 1.5i
|
|
||||||
+field allowed values
|
|
||||||
+.br
|
|
||||||
+----- --------------
|
|
||||||
+.br
|
|
||||||
+minute 0-59
|
|
||||||
+.br
|
|
||||||
+hour 0-23
|
|
||||||
+.br
|
|
||||||
+day of month 1-31
|
|
||||||
+.br
|
|
||||||
+month 1-12
|
|
||||||
+.br
|
|
||||||
+day of week 0-6 (0 is Sunday)
|
|
||||||
+.br
|
|
||||||
+.PP
|
|
||||||
+
|
|
||||||
+The cron syntax is limited to * or specific numbers. Ranges are not supported.
|
|
||||||
+
|
|
||||||
+.TP
|
|
||||||
+\fB\-\-enable\fR
|
|
||||||
+Enable certificate pruning.
|
|
||||||
+.TP
|
|
||||||
+\fB\-\-disable\fR
|
|
||||||
+Disable certificate pruning.
|
|
||||||
+.TP
|
|
||||||
+\fB\-\-cron=CRON\fR
|
|
||||||
+Configure the pruning cron job. The syntax is similar to crontab(5) syntax.
|
|
||||||
+For example, "0 0 1 * *" schedules the job to run at 12:00am on the first
|
|
||||||
+day of each month.
|
|
||||||
+.TP
|
|
||||||
+\fB\-\-certretention=CERTRETENTION\fR
|
|
||||||
+Certificate retention time. The default is 30.
|
|
||||||
+.TP
|
|
||||||
+\fB\-\-certretentionunit=CERTRETENTIONUNIT\fR
|
|
||||||
+Certificate retention units. Valid units are: minute, hour, day, year.
|
|
||||||
+The default is days.
|
|
||||||
+.TP
|
|
||||||
+\fB\-\-certsearchsizelimit=CERTSEARCHSIZELIMIT\fR
|
|
||||||
+LDAP search size limit searching for expired certificates. The default is 1000. This is a client-side limit. There may be additional server-side limitations.
|
|
||||||
+.TP
|
|
||||||
+\fB\-\-certsearchtimelimit=CERTSEARCHTIMELIMIT\fR
|
|
||||||
+LDAP search time limit searching for expired certificates. The default is 0, no limit. This is a client-side limit. There may be additional server-side limitations.
|
|
||||||
+.TP
|
|
||||||
+\fB\-\-requestretention=REQUESTRETENTION\fR
|
|
||||||
+Request retention time. The default is 30.
|
|
||||||
+.TP
|
|
||||||
+\fB\-\-requestretentionunit=REQUESTRETENTIONUNIT\fR
|
|
||||||
+Request retention units. Valid units are: minute, hour, day, year.
|
|
||||||
+The default is days.
|
|
||||||
+.TP
|
|
||||||
+\fB\-\-requestsearchsizelimit=REQUESTSEARCHSIZELIMIT\fR
|
|
||||||
+LDAP search size limit searching for unfulfilled requests. The default is 1000. There may be additional server-side limitations.
|
|
||||||
+.TP
|
|
||||||
+\fB\-\-requestsearchtimelimit=REQUESTSEARCHTIMELIMIT\fR
|
|
||||||
+LDAP search time limit searching for unfulfilled requests. The default is 0, no limit. There may be additional server-side limitations.
|
|
||||||
+.TP
|
|
||||||
+\fB\-\-config\-show\fR
|
|
||||||
+Show the current pruning configuration
|
|
||||||
+.TP
|
|
||||||
+\fB\-\-run\fR
|
|
||||||
+Run the pruning job now. The IPA RA certificate is used to authenticate to the PKI REST backend.
|
|
||||||
+
|
|
||||||
|
|
||||||
.SH "EXIT STATUS"
|
|
||||||
0 if the command was successful
|
|
||||||
diff --git a/ipaserver/install/ipa_acme_manage.py b/ipaserver/install/ipa_acme_manage.py
|
|
||||||
index 0474b9f4a051063ac6df41a81877a2af9d4a2096..b7b2111d9edcec2580aa4a485d7a7340146ff065 100644
|
|
||||||
--- a/ipaserver/install/ipa_acme_manage.py
|
|
||||||
+++ b/ipaserver/install/ipa_acme_manage.py
|
|
||||||
@@ -2,7 +2,12 @@
|
|
||||||
# Copyright (C) 2020 FreeIPA Contributors see COPYING for license
|
|
||||||
#
|
|
||||||
|
|
||||||
+
|
|
||||||
import enum
|
|
||||||
+import pki.util
|
|
||||||
+import logging
|
|
||||||
+
|
|
||||||
+from optparse import OptionGroup # pylint: disable=deprecated-module
|
|
||||||
|
|
||||||
from ipalib import api, errors, x509
|
|
||||||
from ipalib import _
|
|
||||||
@@ -10,10 +15,64 @@ from ipalib.facts import is_ipa_configured
|
|
||||||
from ipaplatform.paths import paths
|
|
||||||
from ipapython.admintool import AdminTool
|
|
||||||
from ipapython import cookie, dogtag
|
|
||||||
+from ipapython.ipautil import run
|
|
||||||
+from ipapython.certdb import NSSDatabase, EXTERNAL_CA_TRUST_FLAGS
|
|
||||||
from ipaserver.install import cainstance
|
|
||||||
+from ipaserver.install.ca import lookup_random_serial_number_version
|
|
||||||
|
|
||||||
from ipaserver.plugins.dogtag import RestClient
|
|
||||||
|
|
||||||
+logger = logging.getLogger(__name__)
|
|
||||||
+
|
|
||||||
+default_pruning_options = {
|
|
||||||
+ 'certRetentionTime': '30',
|
|
||||||
+ 'certRetentionUnit': 'day',
|
|
||||||
+ 'certSearchSizeLimit': '1000',
|
|
||||||
+ 'certSearchTimeLimit': '0',
|
|
||||||
+ 'requestRetentionTime': 'day',
|
|
||||||
+ 'requestRetentionUnit': '30',
|
|
||||||
+ 'requestSearchSizeLimit': '1000',
|
|
||||||
+ 'requestSearchTimeLimit': '0',
|
|
||||||
+ 'cron': ''
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+pruning_labels = {
|
|
||||||
+ 'certRetentionTime': 'Certificate Retention Time',
|
|
||||||
+ 'certRetentionUnit': 'Certificate Retention Unit',
|
|
||||||
+ 'certSearchSizeLimit': 'Certificate Search Size Limit',
|
|
||||||
+ 'certSearchTimeLimit': 'Certificate Search Time Limit',
|
|
||||||
+ 'requestRetentionTime': 'Request Retention Time',
|
|
||||||
+ 'requestRetentionUnit': 'Request Retention Unit',
|
|
||||||
+ 'requestSearchSizeLimit': 'Request Search Size Limit',
|
|
||||||
+ 'requestSearchTimeLimit': 'Request Search Time Limit',
|
|
||||||
+ 'cron': 'cron Schedule'
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+def validate_range(val, min, max):
|
|
||||||
+ """dogtag appears to have no error checking in the cron
|
|
||||||
+ entry so do some minimum amount of validation. It is
|
|
||||||
+ left as an exercise for the user to do month/day
|
|
||||||
+ validation so requesting Feb 31 will be accepted.
|
|
||||||
+
|
|
||||||
+ Only * and a number within a min/max range are allowed.
|
|
||||||
+ """
|
|
||||||
+ if val == '*':
|
|
||||||
+ return
|
|
||||||
+
|
|
||||||
+ if '-' in val or '/' in val:
|
|
||||||
+ raise ValueError(f"{val} ranges are not supported")
|
|
||||||
+
|
|
||||||
+ try:
|
|
||||||
+ int(val)
|
|
||||||
+ except ValueError:
|
|
||||||
+ # raise a clearer error
|
|
||||||
+ raise ValueError(f"{val} is not a valid integer")
|
|
||||||
+
|
|
||||||
+ if int(val) < min or int(val) > max:
|
|
||||||
+ raise ValueError(f"{val} not within the range {min}-{max}")
|
|
||||||
+
|
|
||||||
+
|
|
||||||
# Manages the FreeIPA ACME service on a per-server basis.
|
|
||||||
#
|
|
||||||
# This program is a stop-gap until the deployment-wide management of
|
|
||||||
@@ -66,32 +125,121 @@ class acme_state(RestClient):
|
|
||||||
status, unused, _unused = self._request('/acme/disable',
|
|
||||||
headers=headers)
|
|
||||||
if status != 200:
|
|
||||||
- raise RuntimeError('Failed to disble ACME')
|
|
||||||
+ raise RuntimeError('Failed to disable ACME')
|
|
||||||
|
|
||||||
|
|
||||||
class Command(enum.Enum):
|
|
||||||
ENABLE = 'enable'
|
|
||||||
DISABLE = 'disable'
|
|
||||||
STATUS = 'status'
|
|
||||||
+ PRUNE = 'pruning'
|
|
||||||
|
|
||||||
|
|
||||||
class IPAACMEManage(AdminTool):
|
|
||||||
command_name = "ipa-acme-manage"
|
|
||||||
- usage = "%prog [enable|disable|status]"
|
|
||||||
+ usage = "%prog [enable|disable|status|pruning]"
|
|
||||||
description = "Manage the IPA ACME service"
|
|
||||||
|
|
||||||
+ @classmethod
|
|
||||||
+ def add_options(cls, parser):
|
|
||||||
+
|
|
||||||
+ group = OptionGroup(parser, 'Pruning')
|
|
||||||
+ group.add_option(
|
|
||||||
+ "--enable", dest="enable", action="store_true",
|
|
||||||
+ default=False, help="Enable certificate pruning")
|
|
||||||
+ group.add_option(
|
|
||||||
+ "--disable", dest="disable", action="store_true",
|
|
||||||
+ default=False, help="Disable certificate pruning")
|
|
||||||
+ group.add_option(
|
|
||||||
+ "--cron", dest="cron", action="store",
|
|
||||||
+ default=None, help="Configure the pruning cron job")
|
|
||||||
+ group.add_option(
|
|
||||||
+ "--certretention", dest="certretention", action="store",
|
|
||||||
+ default=None, help="Certificate retention time", type=int)
|
|
||||||
+ group.add_option(
|
|
||||||
+ "--certretentionunit", dest="certretentionunit", action="store",
|
|
||||||
+ choices=['minute', 'hour', 'day', 'year'],
|
|
||||||
+ default=None, help="Certificate retention units")
|
|
||||||
+ group.add_option(
|
|
||||||
+ "--certsearchsizelimit", dest="certsearchsizelimit",
|
|
||||||
+ action="store",
|
|
||||||
+ default=None, help="LDAP search size limit", type=int)
|
|
||||||
+ group.add_option(
|
|
||||||
+ "--certsearchtimelimit", dest="certsearchtimelimit", action="store",
|
|
||||||
+ default=None, help="LDAP search time limit", type=int)
|
|
||||||
+ group.add_option(
|
|
||||||
+ "--requestretention", dest="requestretention", action="store",
|
|
||||||
+ default=None, help="Request retention time", type=int)
|
|
||||||
+ group.add_option(
|
|
||||||
+ "--requestretentionunit", dest="requestretentionunit",
|
|
||||||
+ choices=['minute', 'hour', 'day', 'year'],
|
|
||||||
+ action="store", default=None, help="Request retention units")
|
|
||||||
+ group.add_option(
|
|
||||||
+ "--requestsearchsizelimit", dest="requestsearchsizelimit",
|
|
||||||
+ action="store",
|
|
||||||
+ default=None, help="LDAP search size limit", type=int)
|
|
||||||
+ group.add_option(
|
|
||||||
+ "--requestsearchtimelimit", dest="requestsearchtimelimit",
|
|
||||||
+ action="store",
|
|
||||||
+ default=None, help="LDAP search time limit", type=int)
|
|
||||||
+ group.add_option(
|
|
||||||
+ "--config-show", dest="config_show", action="store_true",
|
|
||||||
+ default=False, help="Show the current pruning configuration")
|
|
||||||
+ group.add_option(
|
|
||||||
+ "--run", dest="run", action="store_true",
|
|
||||||
+ default=False, help="Run the pruning job now")
|
|
||||||
+ parser.add_option_group(group)
|
|
||||||
+ super(IPAACMEManage, cls).add_options(parser, debug_option=True)
|
|
||||||
+
|
|
||||||
+
|
|
||||||
def validate_options(self):
|
|
||||||
- # needs root now - if/when this program changes to an API
|
|
||||||
- # wrapper we will no longer need root.
|
|
||||||
super(IPAACMEManage, self).validate_options(needs_root=True)
|
|
||||||
|
|
||||||
if len(self.args) < 1:
|
|
||||||
self.option_parser.error(f'missing command argument')
|
|
||||||
- else:
|
|
||||||
- try:
|
|
||||||
- self.command = Command(self.args[0])
|
|
||||||
- except ValueError:
|
|
||||||
- self.option_parser.error(f'unknown command "{self.args[0]}"')
|
|
||||||
+
|
|
||||||
+ if self.args[0] == "pruning":
|
|
||||||
+ if self.options.enable and self.options.disable:
|
|
||||||
+ self.option_parser.error("Cannot both enable and disable")
|
|
||||||
+ elif (
|
|
||||||
+ any(
|
|
||||||
+ [
|
|
||||||
+ self.options.enable,
|
|
||||||
+ self.options.disable,
|
|
||||||
+ self.options.cron,
|
|
||||||
+ self.options.certretention,
|
|
||||||
+ self.options.certretentionunit,
|
|
||||||
+ self.options.requestretention,
|
|
||||||
+ self.options.requestretentionunit,
|
|
||||||
+ self.options.certsearchsizelimit,
|
|
||||||
+ self.options.certsearchtimelimit,
|
|
||||||
+ self.options.requestsearchsizelimit,
|
|
||||||
+ self.options.requestsearchtimelimit,
|
|
||||||
+ ]
|
|
||||||
+ )
|
|
||||||
+ and (self.options.config_show or self.options.run)
|
|
||||||
+ ):
|
|
||||||
+
|
|
||||||
+ self.option_parser.error(
|
|
||||||
+ "Cannot change and show config or run at the same time"
|
|
||||||
+ )
|
|
||||||
+ elif self.options.cron:
|
|
||||||
+ if len(self.options.cron.split()) != 5:
|
|
||||||
+ self.option_parser.error("Invalid format for --cron")
|
|
||||||
+ # dogtag does no validation when setting an option so
|
|
||||||
+ # do the minimum. The dogtag cron is limited compared to
|
|
||||||
+ # crontab(5).
|
|
||||||
+ opt = self.options.cron.split()
|
|
||||||
+ validate_range(opt[0], 0, 59)
|
|
||||||
+ validate_range(opt[1], 0, 23)
|
|
||||||
+ validate_range(opt[2], 1, 31)
|
|
||||||
+ validate_range(opt[3], 1, 12)
|
|
||||||
+ validate_range(opt[4], 0, 6)
|
|
||||||
+
|
|
||||||
+ try:
|
|
||||||
+ self.command = Command(self.args[0])
|
|
||||||
+ except ValueError:
|
|
||||||
+ self.option_parser.error(f'unknown command "{self.args[0]}"')
|
|
||||||
|
|
||||||
def check_san_status(self):
|
|
||||||
"""
|
|
||||||
@@ -100,6 +248,140 @@ class IPAACMEManage(AdminTool):
|
|
||||||
cert = x509.load_certificate_from_file(paths.HTTPD_CERT_FILE)
|
|
||||||
cainstance.check_ipa_ca_san(cert)
|
|
||||||
|
|
||||||
+ def pruning(self):
|
|
||||||
+ def run_pki_server(command, directive, prefix, value=None):
|
|
||||||
+ """Take a set of arguments to append to pki-server"""
|
|
||||||
+ args = [
|
|
||||||
+ 'pki-server', command,
|
|
||||||
+ f'{prefix}.{directive}'
|
|
||||||
+ ]
|
|
||||||
+ if value:
|
|
||||||
+ args.extend([str(value)])
|
|
||||||
+ logger.debug(args)
|
|
||||||
+ result = run(args, raiseonerr=False, capture_output=True,
|
|
||||||
+ capture_error=True)
|
|
||||||
+ if result.returncode != 0:
|
|
||||||
+ raise RuntimeError(result.error_output)
|
|
||||||
+ return result
|
|
||||||
+
|
|
||||||
+ def ca_config_set(directive, value,
|
|
||||||
+ prefix='jobsScheduler.job.pruning'):
|
|
||||||
+ run_pki_server('ca-config-set', directive, prefix, value)
|
|
||||||
+ # ca-config-set always succeeds, even if the option is
|
|
||||||
+ # not supported.
|
|
||||||
+ newvalue = ca_config_show(directive)
|
|
||||||
+ if str(value) != newvalue.strip():
|
|
||||||
+ raise RuntimeError('Updating %s failed' % directive)
|
|
||||||
+
|
|
||||||
+ def ca_config_show(directive):
|
|
||||||
+ result = run_pki_server('ca-config-show', directive,
|
|
||||||
+ prefix='jobsScheduler.job.pruning')
|
|
||||||
+ return result.output.strip()
|
|
||||||
+
|
|
||||||
+ def config_show():
|
|
||||||
+ status = ca_config_show('enabled')
|
|
||||||
+ if status.strip() == 'true':
|
|
||||||
+ print("Status: enabled")
|
|
||||||
+ else:
|
|
||||||
+ print("Status: disabled")
|
|
||||||
+ for option in (
|
|
||||||
+ 'certRetentionTime', 'certRetentionUnit',
|
|
||||||
+ 'certSearchSizeLimit', 'certSearchTimeLimit',
|
|
||||||
+ 'requestRetentionTime', 'requestRetentionUnit',
|
|
||||||
+ 'requestSearchSizeLimit', 'requestSearchTimeLimit',
|
|
||||||
+ 'cron',
|
|
||||||
+ ):
|
|
||||||
+ value = ca_config_show(option)
|
|
||||||
+ if value:
|
|
||||||
+ print("{}: {}".format(pruning_labels[option], value))
|
|
||||||
+ else:
|
|
||||||
+ print("{}: {}".format(pruning_labels[option],
|
|
||||||
+ default_pruning_options[option]))
|
|
||||||
+
|
|
||||||
+ def run_pruning():
|
|
||||||
+ """Run the pruning job manually"""
|
|
||||||
+
|
|
||||||
+ with NSSDatabase() as tmpdb:
|
|
||||||
+ print("Preparing...")
|
|
||||||
+ tmpdb.create_db()
|
|
||||||
+ tmpdb.import_files((paths.RA_AGENT_PEM, paths.RA_AGENT_KEY),
|
|
||||||
+ import_keys=True)
|
|
||||||
+ tmpdb.import_files((paths.IPA_CA_CRT,))
|
|
||||||
+ for nickname, trust_flags in tmpdb.list_certs():
|
|
||||||
+ if trust_flags.has_key:
|
|
||||||
+ ra_nickname = nickname
|
|
||||||
+ continue
|
|
||||||
+ # external is suffucient for our purposes: C,,
|
|
||||||
+ tmpdb.trust_root_cert(nickname, EXTERNAL_CA_TRUST_FLAGS)
|
|
||||||
+ print("Starting job...")
|
|
||||||
+ args = ['pki', '-C', tmpdb.pwd_file, '-d', tmpdb.secdir,
|
|
||||||
+ '-n', ra_nickname,
|
|
||||||
+ 'ca-job-start', 'pruning']
|
|
||||||
+ logger.debug(args)
|
|
||||||
+ run(args, stdin='y')
|
|
||||||
+
|
|
||||||
+ pki_version = pki.util.Version(pki.specification_version())
|
|
||||||
+ if pki_version < pki.util.Version("11.3.0"):
|
|
||||||
+ raise RuntimeError(
|
|
||||||
+ 'Certificate pruning is not supported in PKI version %s'
|
|
||||||
+ % pki_version
|
|
||||||
+ )
|
|
||||||
+
|
|
||||||
+ if lookup_random_serial_number_version(api) == 0:
|
|
||||||
+ raise RuntimeError(
|
|
||||||
+ 'Certificate pruning requires random serial numbers'
|
|
||||||
+ )
|
|
||||||
+
|
|
||||||
+ if self.options.config_show:
|
|
||||||
+ config_show()
|
|
||||||
+ return
|
|
||||||
+
|
|
||||||
+ if self.options.run:
|
|
||||||
+ run_pruning()
|
|
||||||
+ return
|
|
||||||
+
|
|
||||||
+ # Don't play the enable/disable at the same time game
|
|
||||||
+ if self.options.enable:
|
|
||||||
+ ca_config_set('owner', 'ipara')
|
|
||||||
+ ca_config_set('enabled', 'true')
|
|
||||||
+ ca_config_set('enabled', 'true', 'jobsScheduler')
|
|
||||||
+ elif self.options.disable:
|
|
||||||
+ ca_config_set('enabled', 'false')
|
|
||||||
+
|
|
||||||
+ # pki-server ca-config-set can only set one option at a time so
|
|
||||||
+ # loop through all the options and set what is there.
|
|
||||||
+ if self.options.certretention:
|
|
||||||
+ ca_config_set('certRetentionTime',
|
|
||||||
+ self.options.certretention)
|
|
||||||
+ if self.options.certretentionunit:
|
|
||||||
+ ca_config_set('certRetentionUnit',
|
|
||||||
+ self.options.certretentionunit)
|
|
||||||
+ if self.options.certsearchtimelimit:
|
|
||||||
+ ca_config_set('certSearchTimeLimit',
|
|
||||||
+ self.options.certsearchtimelimit)
|
|
||||||
+ if self.options.certsearchsizelimit:
|
|
||||||
+ ca_config_set('certSearchSizeLimit',
|
|
||||||
+ self.options.certsearchsizelimit)
|
|
||||||
+ if self.options.requestretention:
|
|
||||||
+ ca_config_set('requestRetentionTime',
|
|
||||||
+ self.options.requestretention)
|
|
||||||
+ if self.options.requestretentionunit:
|
|
||||||
+ ca_config_set('requestRetentionUnit',
|
|
||||||
+ self.options.requestretentionunit)
|
|
||||||
+ if self.options.requestsearchsizelimit:
|
|
||||||
+ ca_config_set('requestSearchSizeLimit',
|
|
||||||
+ self.options.requestsearchsizelimit)
|
|
||||||
+ if self.options.requestsearchtimelimit:
|
|
||||||
+ ca_config_set('requestSearchTimeLimit',
|
|
||||||
+ self.options.requestsearchtimelimit)
|
|
||||||
+ if self.options.cron:
|
|
||||||
+ ca_config_set('cron', self.options.cron)
|
|
||||||
+
|
|
||||||
+ config_show()
|
|
||||||
+
|
|
||||||
+ print("The CA service must be restarted for changes to take effect")
|
|
||||||
+
|
|
||||||
+
|
|
||||||
def run(self):
|
|
||||||
if not is_ipa_configured():
|
|
||||||
print("IPA is not configured.")
|
|
||||||
@@ -123,7 +405,8 @@ class IPAACMEManage(AdminTool):
|
|
||||||
elif self.command == Command.STATUS:
|
|
||||||
status = "enabled" if dogtag.acme_status() else "disabled"
|
|
||||||
print("ACME is {}".format(status))
|
|
||||||
- return 0
|
|
||||||
+ elif self.command == Command.PRUNE:
|
|
||||||
+ self.pruning()
|
|
||||||
else:
|
|
||||||
raise RuntimeError('programmer error: unhandled enum case')
|
|
||||||
|
|
||||||
diff --git a/ipatests/test_integration/test_acme.py b/ipatests/test_integration/test_acme.py
|
|
||||||
index 15d7543cfb0fa0fcb921166f7cd8f13d0535a41d..93e785d8febd9fa8d7b3ef87ecb3f2eb42ac5da2 100644
|
|
||||||
--- a/ipatests/test_integration/test_acme.py
|
|
||||||
+++ b/ipatests/test_integration/test_acme.py
|
|
||||||
@@ -12,6 +12,9 @@ from ipalib.constants import IPA_CA_RECORD
|
|
||||||
from ipatests.test_integration.base import IntegrationTest
|
|
||||||
from ipatests.pytest_ipa.integration import tasks
|
|
||||||
from ipatests.test_integration.test_caless import CALessBase, ipa_certs_cleanup
|
|
||||||
+from ipatests.test_integration.test_random_serial_numbers import (
|
|
||||||
+ pki_supports_RSNv3
|
|
||||||
+)
|
|
||||||
from ipaplatform.osinfo import osinfo
|
|
||||||
from ipaplatform.paths import paths
|
|
||||||
from ipatests.test_integration.test_external_ca import (
|
|
||||||
@@ -388,6 +391,16 @@ class TestACME(CALessBase):
|
|
||||||
status = check_acme_status(self.replicas[0], 'disabled')
|
|
||||||
assert status == 'disabled'
|
|
||||||
|
|
||||||
+ def test_acme_pruning_no_random_serial(self):
|
|
||||||
+ """This ACME install is configured without random serial
|
|
||||||
+ numbers. Verify that we can't enable pruning on it."""
|
|
||||||
+ self.master.run_command(['ipa-acme-manage', 'enable'])
|
|
||||||
+ result = self.master.run_command(
|
|
||||||
+ ['ipa-acme-manage', 'pruning', '--enable'],
|
|
||||||
+ raiseonerr=False)
|
|
||||||
+ assert result.returncode == 1
|
|
||||||
+ assert "requires random serial numbers" in result.stderr_text
|
|
||||||
+
|
|
||||||
@server_install_teardown
|
|
||||||
def test_third_party_certs(self):
|
|
||||||
"""Require ipa-ca SAN on replacement web certificates"""
|
|
||||||
@@ -630,3 +643,148 @@ class TestACMERenew(IntegrationTest):
|
|
||||||
renewed_expiry = cert.not_valid_after
|
|
||||||
|
|
||||||
assert initial_expiry != renewed_expiry
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+class TestACMEPrune(IntegrationTest):
|
|
||||||
+ """Validate that ipa-acme-manage configures dogtag for pruning"""
|
|
||||||
+
|
|
||||||
+ random_serial = True
|
|
||||||
+
|
|
||||||
+ @classmethod
|
|
||||||
+ def install(cls, mh):
|
|
||||||
+ if not pki_supports_RSNv3(mh.master):
|
|
||||||
+ raise pytest.skip("RNSv3 not supported")
|
|
||||||
+ tasks.install_master(cls.master, setup_dns=True,
|
|
||||||
+ random_serial=True)
|
|
||||||
+
|
|
||||||
+ @classmethod
|
|
||||||
+ def uninstall(cls, mh):
|
|
||||||
+ if not pki_supports_RSNv3(mh.master):
|
|
||||||
+ raise pytest.skip("RSNv3 not supported")
|
|
||||||
+ super(TestACMEPrune, cls).uninstall(mh)
|
|
||||||
+
|
|
||||||
+ def test_enable_pruning(self):
|
|
||||||
+ if (tasks.get_pki_version(self.master)
|
|
||||||
+ < tasks.parse_version('11.3.0')):
|
|
||||||
+ raise pytest.skip("Certificate pruning is not available")
|
|
||||||
+ cs_cfg = self.master.get_file_contents(paths.CA_CS_CFG_PATH)
|
|
||||||
+ assert "jobsScheduler.job.pruning.enabled=false".encode() in cs_cfg
|
|
||||||
+
|
|
||||||
+ self.master.run_command(['ipa-acme-manage', 'pruning', '--enable'])
|
|
||||||
+
|
|
||||||
+ cs_cfg = self.master.get_file_contents(paths.CA_CS_CFG_PATH)
|
|
||||||
+ assert "jobsScheduler.enabled=true".encode() in cs_cfg
|
|
||||||
+ assert "jobsScheduler.job.pruning.enabled=true".encode() in cs_cfg
|
|
||||||
+ assert "jobsScheduler.job.pruning.owner=ipara".encode() in cs_cfg
|
|
||||||
+
|
|
||||||
+ def test_pruning_options(self):
|
|
||||||
+ if (tasks.get_pki_version(self.master)
|
|
||||||
+ < tasks.parse_version('11.3.0')):
|
|
||||||
+ raise pytest.skip("Certificate pruning is not available")
|
|
||||||
+
|
|
||||||
+ self.master.run_command(
|
|
||||||
+ ['ipa-acme-manage', 'pruning',
|
|
||||||
+ '--certretention=60',
|
|
||||||
+ '--certretentionunit=minute',
|
|
||||||
+ '--certsearchsizelimit=2000',
|
|
||||||
+ '--certsearchtimelimit=5',]
|
|
||||||
+ )
|
|
||||||
+ cs_cfg = self.master.get_file_contents(paths.CA_CS_CFG_PATH)
|
|
||||||
+ assert (
|
|
||||||
+ "jobsScheduler.job.pruning.certRetentionTime=60".encode()
|
|
||||||
+ in cs_cfg
|
|
||||||
+ )
|
|
||||||
+ assert (
|
|
||||||
+ "jobsScheduler.job.pruning.certRetentionUnit=minute".encode()
|
|
||||||
+ in cs_cfg
|
|
||||||
+ )
|
|
||||||
+ assert (
|
|
||||||
+ "jobsScheduler.job.pruning.certSearchSizeLimit=2000".encode()
|
|
||||||
+ in cs_cfg
|
|
||||||
+ )
|
|
||||||
+ assert (
|
|
||||||
+ "jobsScheduler.job.pruning.certSearchTimeLimit=5".encode()
|
|
||||||
+ in cs_cfg
|
|
||||||
+ )
|
|
||||||
+
|
|
||||||
+ self.master.run_command(
|
|
||||||
+ ['ipa-acme-manage', 'pruning',
|
|
||||||
+ '--requestretention=60',
|
|
||||||
+ '--requestretentionunit=minute',
|
|
||||||
+ '--requestresearchsizelimit=2000',
|
|
||||||
+ '--requestsearchtimelimit=5',]
|
|
||||||
+ )
|
|
||||||
+ cs_cfg = self.master.get_file_contents(paths.CA_CS_CFG_PATH)
|
|
||||||
+ assert (
|
|
||||||
+ "jobsScheduler.job.pruning.requestRetentionTime=60".encode()
|
|
||||||
+ in cs_cfg
|
|
||||||
+ )
|
|
||||||
+ assert (
|
|
||||||
+ "jobsScheduler.job.pruning.requestRetentionUnit=minute".encode()
|
|
||||||
+ in cs_cfg
|
|
||||||
+ )
|
|
||||||
+ assert (
|
|
||||||
+ "jobsScheduler.job.pruning.requestSearchSizeLimit=2000".encode()
|
|
||||||
+ in cs_cfg
|
|
||||||
+ )
|
|
||||||
+ assert (
|
|
||||||
+ "jobsScheduler.job.pruning.requestSearchTimeLimit=5".encode()
|
|
||||||
+ in cs_cfg
|
|
||||||
+ )
|
|
||||||
+
|
|
||||||
+ self.master.run_command(
|
|
||||||
+ ['ipa-acme-manage', 'pruning',
|
|
||||||
+ '--cron="0 23 1 * *',]
|
|
||||||
+ )
|
|
||||||
+ cs_cfg = self.master.get_file_contents(paths.CA_CS_CFG_PATH)
|
|
||||||
+ assert (
|
|
||||||
+ "jobsScheduler.job.pruning.cron=0 23 1 * *".encode()
|
|
||||||
+ in cs_cfg
|
|
||||||
+ )
|
|
||||||
+
|
|
||||||
+ def test_pruning_negative_options(self):
|
|
||||||
+ """Negative option testing for things we directly cover"""
|
|
||||||
+ if (tasks.get_pki_version(self.master)
|
|
||||||
+ < tasks.parse_version('11.3.0')):
|
|
||||||
+ raise pytest.skip("Certificate pruning is not available")
|
|
||||||
+
|
|
||||||
+ result = self.master.run_command(
|
|
||||||
+ ['ipa-acme-manage', 'pruning',
|
|
||||||
+ '--enable', '--disable'],
|
|
||||||
+ raiseonerr=False
|
|
||||||
+ )
|
|
||||||
+ assert result.returncode == 1
|
|
||||||
+ assert "Cannot both enable and disable" in result.stderr_text
|
|
||||||
+
|
|
||||||
+ for cmd in ('--config-show', '--run'):
|
|
||||||
+ result = self.master.run_command(
|
|
||||||
+ ['ipa-acme-manage', 'pruning',
|
|
||||||
+ cmd, '--enable'],
|
|
||||||
+ raiseonerr=False
|
|
||||||
+ )
|
|
||||||
+ assert result.returncode == 1
|
|
||||||
+ assert "Cannot change and show config" in result.stderr_text
|
|
||||||
+
|
|
||||||
+ result = self.master.run_command(
|
|
||||||
+ ['ipa-acme-manage', 'pruning',
|
|
||||||
+ '--cron="* *"'],
|
|
||||||
+ raiseonerr=False
|
|
||||||
+ )
|
|
||||||
+ assert result.returncode == 1
|
|
||||||
+ assert "Invalid format format --cron" in result.stderr_text
|
|
||||||
+
|
|
||||||
+ result = self.master.run_command(
|
|
||||||
+ ['ipa-acme-manage', 'pruning',
|
|
||||||
+ '--cron="100 * * * *"'],
|
|
||||||
+ raiseonerr=False
|
|
||||||
+ )
|
|
||||||
+ assert result.returncode == 1
|
|
||||||
+ assert "100 not within the range 0-59" in result.stderr_text
|
|
||||||
+
|
|
||||||
+ result = self.master.run_command(
|
|
||||||
+ ['ipa-acme-manage', 'pruning',
|
|
||||||
+ '--cron="10 1-5 * * *"'],
|
|
||||||
+ raiseonerr=False
|
|
||||||
+ )
|
|
||||||
+ assert result.returncode == 1
|
|
||||||
+ assert "1-5 ranges are not supported" in result.stderr_text
|
|
||||||
--
|
|
||||||
2.39.1
|
|
||||||
|
|
@ -0,0 +1,129 @@
|
|||||||
|
From f93a6d3ff52247ce5e582816fec689b8901fc984 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
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 <flo@redhat.com>
|
||||||
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
---
|
||||||
|
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 <path> 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
|
||||||
|
|
@ -1,138 +0,0 @@
|
|||||||
From f10d1a0f84ed0f16ab4a1469f16ffadb3e79e59e Mon Sep 17 00:00:00 2001
|
|
||||||
From: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
Date: Fri, 27 Jan 2023 14:05:37 -0500
|
|
||||||
Subject: [PATCH] doc: add the --run command for manual job execution
|
|
||||||
|
|
||||||
A manual method was mentioned with no specificity. Include
|
|
||||||
the --run command. Also update the troubleshooting section
|
|
||||||
to show what failure to restart the CA after configuration
|
|
||||||
looks like.
|
|
||||||
|
|
||||||
Import the IPA CA chain for manual execution.
|
|
||||||
|
|
||||||
Also fix up some $ -> # to indicate root is needed.
|
|
||||||
|
|
||||||
Related: https://pagure.io/freeipa/issue/9294
|
|
||||||
|
|
||||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
---
|
|
||||||
doc/designs/expired_certificate_pruning.md | 46 +++++++++++++++-------
|
|
||||||
1 file changed, 32 insertions(+), 14 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/doc/designs/expired_certificate_pruning.md b/doc/designs/expired_certificate_pruning.md
|
|
||||||
index 2c10d914020d3c12b6abb028323cd6796ec33e00..a23e452696ba2a150c4ad5a3e57360ae0a16a338 100644
|
|
||||||
--- a/doc/designs/expired_certificate_pruning.md
|
|
||||||
+++ b/doc/designs/expired_certificate_pruning.md
|
|
||||||
@@ -139,7 +139,7 @@ No validation of setting February 31st will be done. That will be left to PKI. B
|
|
||||||
|
|
||||||
### Disabling pruning
|
|
||||||
|
|
||||||
-`$ ipa-acme-manage pruning --enable=FALSE`
|
|
||||||
+`# ipa-acme-manage pruning --enable=FALSE`
|
|
||||||
|
|
||||||
This will remove the configuration option for `jobsScheduler.job.pruning.cron` just to be sure it no longer runs.
|
|
||||||
|
|
||||||
@@ -147,46 +147,46 @@ This will remove the configuration option for `jobsScheduler.job.pruning.cron` j
|
|
||||||
|
|
||||||
#### Pruning certificates
|
|
||||||
|
|
||||||
-`$ ipa-acme-manage pruning --certretention=VALUE --certretentionunit=UNIT`
|
|
||||||
+`# ipa-acme-manage pruning --certretention=VALUE --certretentionunit=UNIT`
|
|
||||||
|
|
||||||
will be the equivalent of:
|
|
||||||
|
|
||||||
-`$ pki-server ca-config-set jobsScheduler.job.pruning.certRetentionTime 30`
|
|
||||||
+`# pki-server ca-config-set jobsScheduler.job.pruning.certRetentionTime 30`
|
|
||||||
|
|
||||||
-`$ pki-server ca-config-set jobsScheduler.job.pruning.certRetentionUnit day`
|
|
||||||
+`# pki-server ca-config-set jobsScheduler.job.pruning.certRetentionUnit day`
|
|
||||||
|
|
||||||
The unit will always be required when modifying the time.
|
|
||||||
|
|
||||||
-`$ ipa-acme-manage pruning --certsearchsizelimit=VALUE --certsearchtimelimit=VALUE`
|
|
||||||
+`# ipa-acme-manage pruning --certsearchsizelimit=VALUE --certsearchtimelimit=VALUE`
|
|
||||||
|
|
||||||
will be the equivalent of:
|
|
||||||
|
|
||||||
-`$ pki-server ca-config-set jobsScheduler.job.pruning.certSearchSizeLimit 1000`
|
|
||||||
+`# pki-server ca-config-set jobsScheduler.job.pruning.certSearchSizeLimit 1000`
|
|
||||||
|
|
||||||
-`$ pki-server ca-config-set jobsScheduler.job.pruning.certSearchTimeLimit 0`
|
|
||||||
+`# pki-server ca-config-set jobsScheduler.job.pruning.certSearchTimeLimit 0`
|
|
||||||
|
|
||||||
A value of 0 for searchtimelimit is unlimited.
|
|
||||||
|
|
||||||
#### Pruning requests
|
|
||||||
|
|
||||||
-`$ ipa-acme-manage pruning --requestretention=VALUE --requestretentionunit=UNIT`
|
|
||||||
+`# ipa-acme-manage pruning --requestretention=VALUE --requestretentionunit=UNIT`
|
|
||||||
|
|
||||||
will be the equivalent of:
|
|
||||||
|
|
||||||
-`$ pki-server ca-config-set jobsScheduler.job.pruning.requestRetentionTime 30`
|
|
||||||
+`# pki-server ca-config-set jobsScheduler.job.pruning.requestRetentionTime 30`
|
|
||||||
|
|
||||||
-`$ pki-server ca-config-set jobsScheduler.job.pruning.requestRetentionUnit day`
|
|
||||||
+`# pki-server ca-config-set jobsScheduler.job.pruning.requestRetentionUnit day`
|
|
||||||
|
|
||||||
The unit will always be required when modifying the time.
|
|
||||||
|
|
||||||
-`$ ipa-acme-manage pruning --requestsearchsizelimit=VALUE --requestsearchtimelimit=VALUE`
|
|
||||||
+`# ipa-acme-manage pruning --requestsearchsizelimit=VALUE --requestsearchtimelimit=VALUE`
|
|
||||||
|
|
||||||
|
|
||||||
will be the equivalent of:
|
|
||||||
|
|
||||||
-`$ pki-server ca-config-set jobsScheduler.job.pruning.requestSearchSizeLimit 1000`
|
|
||||||
+`# pki-server ca-config-set jobsScheduler.job.pruning.requestSearchSizeLimit 1000`
|
|
||||||
|
|
||||||
-`$ pki-server ca-config-set jobsScheduler.job.pruning.requestSearchTimeLimit 0`
|
|
||||||
+`# pki-server ca-config-set jobsScheduler.job.pruning.requestSearchTimeLimit 0`
|
|
||||||
|
|
||||||
A value of 0 for searchtimelimit is unlimited.
|
|
||||||
|
|
||||||
@@ -212,10 +212,15 @@ Request search time limit: 0
|
|
||||||
Cron: 0 0 1 * *
|
|
||||||
```
|
|
||||||
|
|
||||||
+### Manual pruning
|
|
||||||
+
|
|
||||||
+`# ipa-acme-manage pruning --run`
|
|
||||||
+
|
|
||||||
+This is useful for testing the configuration or if the user wants to use the system cron or systemd timers for handling automation.
|
|
||||||
+
|
|
||||||
## Implementation
|
|
||||||
|
|
||||||
For online REST operations (login, run job) we will use the `ipaserver/plugins/dogtag.py::RestClient` class to manage the requests. This will take care of the authentication cookie, etc.
|
|
||||||
-
|
|
||||||
The class uses dogtag.https_request() will can take PEM cert and key files as arguments. These will be used for authentication.
|
|
||||||
|
|
||||||
For the non-REST operations (configuration, cron settings) the tool will fork out to pki-server ca-config-set.
|
|
||||||
@@ -239,6 +244,7 @@ Overview of the CLI commands. Example:
|
|
||||||
| ipa-acme-manage pruning | --requestretention=30 --requestretentionunit=day |
|
|
||||||
| ipa-acme-manage pruning | --requestsearchsizelimit=1000 --requestsearchtimelimit=0 |
|
|
||||||
| ipa-acme-manage pruning | --config-show |
|
|
||||||
+| ipa-acme-manage pruning | --run |
|
|
||||||
|
|
||||||
ipa-acme-manage can only be run as root.
|
|
||||||
|
|
||||||
@@ -295,3 +301,15 @@ The PKI debug log will contain job information.
|
|
||||||
2022-12-08 21:15:24 [pruning] INFO: PruningJob: - filter: (&(!(requestState=complete))(requestModifyTime<=1667942124527)(!(requestModifyTime=1667942124527)))
|
|
||||||
2022-12-08 21:15:24 [pruning] INFO: LDAPSession: Searching ou=ca, ou=requests,o=ipaca for (&(!(requestState=complete))(dateOfModify<=20221108211524Z)(!(dateOfModify=20221108211524Z)))
|
|
||||||
```
|
|
||||||
+
|
|
||||||
+### Manual execution fails with Forbidden
|
|
||||||
+
|
|
||||||
+If manually running pruning fails with a message like:
|
|
||||||
+
|
|
||||||
+```console
|
|
||||||
+# ipa-acme-manage pruning --run
|
|
||||||
+CalledProcessError(Command ['pki', '-C', '/tmp/tmppyyd3hfq/pwdfile.txt', '-d', '/tmp/tmppyyd3hfq', '-n', 'CN=IPA RA,O=EXAMPLE.TEST', 'ca-job-start', 'pruning'] returned non-zero exit status 255: 'PKIException: Forbidden\n')
|
|
||||||
+The ipa-acme-manage command failed.
|
|
||||||
+```
|
|
||||||
+
|
|
||||||
+You probably forgot to restart the CA after enabling pruning.
|
|
||||||
--
|
|
||||||
2.39.1
|
|
||||||
|
|
44
SOURCES/0009-Detection-of-PKI-subsystem.patch
Normal file
44
SOURCES/0009-Detection-of-PKI-subsystem.patch
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
From b9a07b1e97ee4e310b50860103872685da540da4 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
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 <flo@redhat.com>
|
||||||
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
---
|
||||||
|
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
|
||||||
|
|
@ -1,43 +0,0 @@
|
|||||||
From d24b69981d94fce7b1e1aa4a5c1ab88a123f96b5 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
Date: Fri, 3 Feb 2023 10:04:31 -0500
|
|
||||||
Subject: [PATCH] tests: add wrapper around ACME RSNv3 test
|
|
||||||
|
|
||||||
This test is located outside of the TestACMEPrune because
|
|
||||||
it enables RSNv3 while the server installed by TestACME doesn't.
|
|
||||||
|
|
||||||
It still needs a wrapper to enforce a version of PKI that
|
|
||||||
supports pruning because that is checked first in the tool.
|
|
||||||
Re-ordering that wouldn't be a good user experience.
|
|
||||||
|
|
||||||
https://pagure.io/freeipa/issue/9322
|
|
||||||
|
|
||||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
---
|
|
||||||
ipatests/test_integration/test_acme.py | 9 ++++++++-
|
|
||||||
1 file changed, 8 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/ipatests/test_integration/test_acme.py b/ipatests/test_integration/test_acme.py
|
|
||||||
index 93e785d8febd9fa8d7b3ef87ecb3f2eb42ac5da2..5ceba05976059de69414a79634d98045c3ab68bb 100644
|
|
||||||
--- a/ipatests/test_integration/test_acme.py
|
|
||||||
+++ b/ipatests/test_integration/test_acme.py
|
|
||||||
@@ -393,7 +393,14 @@ class TestACME(CALessBase):
|
|
||||||
|
|
||||||
def test_acme_pruning_no_random_serial(self):
|
|
||||||
"""This ACME install is configured without random serial
|
|
||||||
- numbers. Verify that we can't enable pruning on it."""
|
|
||||||
+ numbers. Verify that we can't enable pruning on it.
|
|
||||||
+
|
|
||||||
+ This test is located here because by default installs
|
|
||||||
+ don't enable RSNv3.
|
|
||||||
+ """
|
|
||||||
+ if (tasks.get_pki_version(self.master)
|
|
||||||
+ < tasks.parse_version('11.3.0')):
|
|
||||||
+ raise pytest.skip("Certificate pruning is not available")
|
|
||||||
self.master.run_command(['ipa-acme-manage', 'enable'])
|
|
||||||
result = self.master.run_command(
|
|
||||||
['ipa-acme-manage', 'pruning', '--enable'],
|
|
||||||
--
|
|
||||||
2.39.1
|
|
||||||
|
|
164
SOURCES/0010-Upgrade-fix-replica-agreement.patch
Normal file
164
SOURCES/0010-Upgrade-fix-replica-agreement.patch
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
From ad77c4c6512f82019d1970d910647761b60aaedb Mon Sep 17 00:00:00 2001
|
||||||
|
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
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 <flo@redhat.com>
|
||||||
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
---
|
||||||
|
.../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
|
||||||
|
|
@ -1,68 +0,0 @@
|
|||||||
From 2857bc69957bde7e59fff1c66c5a83c7f560616b Mon Sep 17 00:00:00 2001
|
|
||||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
Date: Tue, 31 Jan 2023 15:53:08 +0100
|
|
||||||
Subject: [PATCH] automember-rebuild: add a notice about high CPU usage
|
|
||||||
|
|
||||||
The automember-rebuild task may require high CPU usage
|
|
||||||
if many users/hosts/groups are processed.
|
|
||||||
Add a note in the ipa automember-rebuild CLI output
|
|
||||||
and in the WebUI confirmation message.
|
|
||||||
|
|
||||||
Fixes: https://pagure.io/freeipa/issue/9320
|
|
||||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
|
|
||||||
---
|
|
||||||
install/ui/test/data/i18n_messages.json | 2 +-
|
|
||||||
ipaclient/plugins/automember.py | 8 ++++++++
|
|
||||||
ipaserver/plugins/internal.py | 6 +++++-
|
|
||||||
3 files changed, 14 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/install/ui/test/data/i18n_messages.json b/install/ui/test/data/i18n_messages.json
|
|
||||||
index 49d288326d8cea192a16e93a274599805b0ea666..5b735487bf33805e8f0534d378d1497f05a11be8 100644
|
|
||||||
--- a/install/ui/test/data/i18n_messages.json
|
|
||||||
+++ b/install/ui/test/data/i18n_messages.json
|
|
||||||
@@ -7,7 +7,7 @@
|
|
||||||
"actions": {
|
|
||||||
"apply": "Apply",
|
|
||||||
"automember_rebuild": "Rebuild auto membership",
|
|
||||||
- "automember_rebuild_confirm": "Are you sure you want to rebuild auto membership?",
|
|
||||||
+ "automember_rebuild_confirm": "Are you sure you want to rebuild auto membership? In case of a high number of users, hosts or groups, the operation may require high CPU usage.",
|
|
||||||
"automember_rebuild_success": "Automember rebuild membership task completed",
|
|
||||||
"confirm": "Are you sure you want to proceed with the action?",
|
|
||||||
"delete_confirm": "Are you sure you want to delete ${object}?",
|
|
||||||
diff --git a/ipaclient/plugins/automember.py b/ipaclient/plugins/automember.py
|
|
||||||
index df4a2e5a01744e0ff22c74180e13c2e7dc33fbaa..7108dc948753b9f6a4439842bd75e7c5e064bda6 100644
|
|
||||||
--- a/ipaclient/plugins/automember.py
|
|
||||||
+++ b/ipaclient/plugins/automember.py
|
|
||||||
@@ -34,3 +34,11 @@ class automember_add_condition(MethodOverride):
|
|
||||||
flags=['suppress_empty'],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+@register(override=True, no_fail=True)
|
|
||||||
+class automember_rebuild(MethodOverride):
|
|
||||||
+ def interactive_prompt_callback(self, kw):
|
|
||||||
+ msg = _('IMPORTANT: In case of a high number of users, hosts or '
|
|
||||||
+ 'groups, the operation may require high CPU usage.')
|
|
||||||
+ self.Backend.textui.print_plain(msg)
|
|
||||||
diff --git a/ipaserver/plugins/internal.py b/ipaserver/plugins/internal.py
|
|
||||||
index 5ffa7a281548a0658386f8740dbddd96fd0bc7d6..e1e920f8bb49dd8ba8f30b727111bb1316f6a918 100644
|
|
||||||
--- a/ipaserver/plugins/internal.py
|
|
||||||
+++ b/ipaserver/plugins/internal.py
|
|
||||||
@@ -160,7 +160,11 @@ class i18n_messages(Command):
|
|
||||||
"actions": {
|
|
||||||
"apply": _("Apply"),
|
|
||||||
"automember_rebuild": _("Rebuild auto membership"),
|
|
||||||
- "automember_rebuild_confirm": _("Are you sure you want to rebuild auto membership?"),
|
|
||||||
+ "automember_rebuild_confirm": _(
|
|
||||||
+ "Are you sure you want to rebuild auto membership? In case of "
|
|
||||||
+ "a high number of users, hosts or groups, the operation "
|
|
||||||
+ "may require high CPU usage."
|
|
||||||
+ ),
|
|
||||||
"automember_rebuild_success": _("Automember rebuild membership task completed"),
|
|
||||||
"confirm": _("Are you sure you want to proceed with the action?"),
|
|
||||||
"delete_confirm": _("Are you sure you want to delete ${object}?"),
|
|
||||||
--
|
|
||||||
2.39.1
|
|
||||||
|
|
@ -1,158 +0,0 @@
|
|||||||
From 20ff7c16022793c707f6c2b8fb38a801870bc0e2 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
Date: Wed, 8 Feb 2023 10:42:58 -0500
|
|
||||||
Subject: [PATCH] Fix setting values of 0 in ACME pruning
|
|
||||||
|
|
||||||
Replace comparisons of "if value" with "if value is not None"
|
|
||||||
in order to handle 0.
|
|
||||||
|
|
||||||
Add a short reference to the man page to indicat that a cert
|
|
||||||
or request retention time of 0 means remove at the next
|
|
||||||
execution.
|
|
||||||
|
|
||||||
Also indicate that the search time limit is in seconds.
|
|
||||||
|
|
||||||
Fixes: https://pagure.io/freeipa/issue/9325
|
|
||||||
|
|
||||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
|
|
||||||
---
|
|
||||||
doc/designs/expired_certificate_pruning.md | 4 ++--
|
|
||||||
install/tools/man/ipa-acme-manage.1 | 8 +++----
|
|
||||||
ipaserver/install/ipa_acme_manage.py | 28 +++++++++++-----------
|
|
||||||
3 files changed, 20 insertions(+), 20 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/doc/designs/expired_certificate_pruning.md b/doc/designs/expired_certificate_pruning.md
|
|
||||||
index a23e452696ba2a150c4ad5a3e57360ae0a16a338..35ead7b00145b5df44caf542cba277f0e6e08b6a 100644
|
|
||||||
--- a/doc/designs/expired_certificate_pruning.md
|
|
||||||
+++ b/doc/designs/expired_certificate_pruning.md
|
|
||||||
@@ -67,11 +67,11 @@ There are four values each that can be managed for pruning certificates and requ
|
|
||||||
* expired cert/incomplete request time
|
|
||||||
* time unit
|
|
||||||
* LDAP search size limit
|
|
||||||
-* LDAP search time limit
|
|
||||||
+* LDAP search time limit (in seconds)
|
|
||||||
|
|
||||||
The first two configure when an expired certificate or incomplete request will be deleted. The unit can be one of: minute, hour, day, year. By default it is 30 days.
|
|
||||||
|
|
||||||
-The LDAP limits control how many entries are returned and how long the search can take. By default it is 1000 entries and unlimited time.
|
|
||||||
+The LDAP limits control how many entries are returned and how long the search can take. By default it is 1000 entries and unlimited time (0 == unlimited, unit is seconds).
|
|
||||||
|
|
||||||
### Configuration settings
|
|
||||||
|
|
||||||
diff --git a/install/tools/man/ipa-acme-manage.1 b/install/tools/man/ipa-acme-manage.1
|
|
||||||
index e6cec4e4a7fd460c514a72456a2dc9a2e3682ebd..b8383c14f482698d2bcc8b08f0c0bf5882c3c298 100644
|
|
||||||
--- a/install/tools/man/ipa-acme-manage.1
|
|
||||||
+++ b/install/tools/man/ipa-acme-manage.1
|
|
||||||
@@ -79,7 +79,7 @@ For example, "0 0 1 * *" schedules the job to run at 12:00am on the first
|
|
||||||
day of each month.
|
|
||||||
.TP
|
|
||||||
\fB\-\-certretention=CERTRETENTION\fR
|
|
||||||
-Certificate retention time. The default is 30.
|
|
||||||
+Certificate retention time. The default is 30. A value of 0 will remove expired certificates with no delay.
|
|
||||||
.TP
|
|
||||||
\fB\-\-certretentionunit=CERTRETENTIONUNIT\fR
|
|
||||||
Certificate retention units. Valid units are: minute, hour, day, year.
|
|
||||||
@@ -89,10 +89,10 @@ The default is days.
|
|
||||||
LDAP search size limit searching for expired certificates. The default is 1000. This is a client-side limit. There may be additional server-side limitations.
|
|
||||||
.TP
|
|
||||||
\fB\-\-certsearchtimelimit=CERTSEARCHTIMELIMIT\fR
|
|
||||||
-LDAP search time limit searching for expired certificates. The default is 0, no limit. This is a client-side limit. There may be additional server-side limitations.
|
|
||||||
+LDAP search time limit (seconds) searching for expired certificates. The default is 0, no limit. This is a client-side limit. There may be additional server-side limitations.
|
|
||||||
.TP
|
|
||||||
\fB\-\-requestretention=REQUESTRETENTION\fR
|
|
||||||
-Request retention time. The default is 30.
|
|
||||||
+Request retention time. The default is 30. A value of 0 will remove expired requests with no delay.
|
|
||||||
.TP
|
|
||||||
\fB\-\-requestretentionunit=REQUESTRETENTIONUNIT\fR
|
|
||||||
Request retention units. Valid units are: minute, hour, day, year.
|
|
||||||
@@ -102,7 +102,7 @@ The default is days.
|
|
||||||
LDAP search size limit searching for unfulfilled requests. The default is 1000. There may be additional server-side limitations.
|
|
||||||
.TP
|
|
||||||
\fB\-\-requestsearchtimelimit=REQUESTSEARCHTIMELIMIT\fR
|
|
||||||
-LDAP search time limit searching for unfulfilled requests. The default is 0, no limit. There may be additional server-side limitations.
|
|
||||||
+LDAP search time limit (seconds) searching for unfulfilled requests. The default is 0, no limit. There may be additional server-side limitations.
|
|
||||||
.TP
|
|
||||||
\fB\-\-config\-show\fR
|
|
||||||
Show the current pruning configuration
|
|
||||||
diff --git a/ipaserver/install/ipa_acme_manage.py b/ipaserver/install/ipa_acme_manage.py
|
|
||||||
index b7b2111d9edcec2580aa4a485d7a7340146ff065..e7c35ff6fb5b7a30ac9e2c0c18f8db805cf06ee9 100644
|
|
||||||
--- a/ipaserver/install/ipa_acme_manage.py
|
|
||||||
+++ b/ipaserver/install/ipa_acme_manage.py
|
|
||||||
@@ -207,14 +207,14 @@ class IPAACMEManage(AdminTool):
|
|
||||||
self.options.enable,
|
|
||||||
self.options.disable,
|
|
||||||
self.options.cron,
|
|
||||||
- self.options.certretention,
|
|
||||||
+ self.options.certretention is not None,
|
|
||||||
self.options.certretentionunit,
|
|
||||||
- self.options.requestretention,
|
|
||||||
+ self.options.requestretention is not None,
|
|
||||||
self.options.requestretentionunit,
|
|
||||||
- self.options.certsearchsizelimit,
|
|
||||||
- self.options.certsearchtimelimit,
|
|
||||||
- self.options.requestsearchsizelimit,
|
|
||||||
- self.options.requestsearchtimelimit,
|
|
||||||
+ self.options.certsearchsizelimit is not None,
|
|
||||||
+ self.options.certsearchtimelimit is not None,
|
|
||||||
+ self.options.requestsearchsizelimit is not None,
|
|
||||||
+ self.options.requestsearchtimelimit is not None,
|
|
||||||
]
|
|
||||||
)
|
|
||||||
and (self.options.config_show or self.options.run)
|
|
||||||
@@ -226,7 +226,7 @@ class IPAACMEManage(AdminTool):
|
|
||||||
elif self.options.cron:
|
|
||||||
if len(self.options.cron.split()) != 5:
|
|
||||||
self.option_parser.error("Invalid format for --cron")
|
|
||||||
- # dogtag does no validation when setting an option so
|
|
||||||
+ # dogtag does no validation when setting this option so
|
|
||||||
# do the minimum. The dogtag cron is limited compared to
|
|
||||||
# crontab(5).
|
|
||||||
opt = self.options.cron.split()
|
|
||||||
@@ -255,7 +255,7 @@ class IPAACMEManage(AdminTool):
|
|
||||||
'pki-server', command,
|
|
||||||
f'{prefix}.{directive}'
|
|
||||||
]
|
|
||||||
- if value:
|
|
||||||
+ if value is not None:
|
|
||||||
args.extend([str(value)])
|
|
||||||
logger.debug(args)
|
|
||||||
result = run(args, raiseonerr=False, capture_output=True,
|
|
||||||
@@ -350,28 +350,28 @@ class IPAACMEManage(AdminTool):
|
|
||||||
|
|
||||||
# pki-server ca-config-set can only set one option at a time so
|
|
||||||
# loop through all the options and set what is there.
|
|
||||||
- if self.options.certretention:
|
|
||||||
+ if self.options.certretention is not None:
|
|
||||||
ca_config_set('certRetentionTime',
|
|
||||||
self.options.certretention)
|
|
||||||
if self.options.certretentionunit:
|
|
||||||
ca_config_set('certRetentionUnit',
|
|
||||||
self.options.certretentionunit)
|
|
||||||
- if self.options.certsearchtimelimit:
|
|
||||||
+ if self.options.certsearchtimelimit is not None:
|
|
||||||
ca_config_set('certSearchTimeLimit',
|
|
||||||
self.options.certsearchtimelimit)
|
|
||||||
- if self.options.certsearchsizelimit:
|
|
||||||
+ if self.options.certsearchsizelimit is not None:
|
|
||||||
ca_config_set('certSearchSizeLimit',
|
|
||||||
self.options.certsearchsizelimit)
|
|
||||||
- if self.options.requestretention:
|
|
||||||
+ if self.options.requestretention is not None:
|
|
||||||
ca_config_set('requestRetentionTime',
|
|
||||||
self.options.requestretention)
|
|
||||||
if self.options.requestretentionunit:
|
|
||||||
ca_config_set('requestRetentionUnit',
|
|
||||||
self.options.requestretentionunit)
|
|
||||||
- if self.options.requestsearchsizelimit:
|
|
||||||
+ if self.options.requestsearchsizelimit is not None:
|
|
||||||
ca_config_set('requestSearchSizeLimit',
|
|
||||||
self.options.requestsearchsizelimit)
|
|
||||||
- if self.options.requestsearchtimelimit:
|
|
||||||
+ if self.options.requestsearchtimelimit is not None:
|
|
||||||
ca_config_set('requestSearchTimeLimit',
|
|
||||||
self.options.requestsearchtimelimit)
|
|
||||||
if self.options.cron:
|
|
||||||
--
|
|
||||||
2.39.1
|
|
||||||
|
|
@ -0,0 +1,69 @@
|
|||||||
|
From 3b58487c7b2f8ac133e37e8f90f85ff2fb05bf34 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
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 <flo@redhat.com>
|
||||||
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
---
|
||||||
|
.../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
|
||||||
|
|
@ -1,69 +0,0 @@
|
|||||||
From 4e0ad96fbd9f438c884eeeaa60c2fb0c910a2b61 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
Date: Mon, 11 Jul 2022 14:20:32 -0400
|
|
||||||
Subject: [PATCH] Wipe the ipa-ca DNS record when updating system records
|
|
||||||
|
|
||||||
If a server with a CA has been marked as hidden and
|
|
||||||
contains the last A or AAAA address then that address
|
|
||||||
would remain in the ipa-ca entry.
|
|
||||||
|
|
||||||
This is because update-dns-system-records did not delete
|
|
||||||
values, it just re-computed them. So if no A or AAAA
|
|
||||||
records were found then the existing value was left.
|
|
||||||
|
|
||||||
Fixes: https://pagure.io/freeipa/issue/9195
|
|
||||||
|
|
||||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
|
|
||||||
Reviewed-By: Stanislav Levin <slev@altlinux.org>
|
|
||||||
---
|
|
||||||
ipaserver/dns_data_management.py | 12 +++++++++++-
|
|
||||||
1 file changed, 11 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/ipaserver/dns_data_management.py b/ipaserver/dns_data_management.py
|
|
||||||
index e2bc530ee8a8d7ade853652680c524ccd229205c..aaae5446856aba5e39ca9bb9c03decd434e4f71a 100644
|
|
||||||
--- a/ipaserver/dns_data_management.py
|
|
||||||
+++ b/ipaserver/dns_data_management.py
|
|
||||||
@@ -19,6 +19,7 @@ from dns import (
|
|
||||||
from time import sleep, time
|
|
||||||
|
|
||||||
from ipalib import errors
|
|
||||||
+from ipalib.constants import IPA_CA_RECORD
|
|
||||||
from ipalib.dns import record_name_format
|
|
||||||
from ipapython.dnsutil import DNSName
|
|
||||||
from ipaserver.install import installutils
|
|
||||||
@@ -187,7 +188,7 @@ class IPASystemRecords:
|
|
||||||
|
|
||||||
def __add_ca_records_from_hostname(self, zone_obj, hostname):
|
|
||||||
assert isinstance(hostname, DNSName) and hostname.is_absolute()
|
|
||||||
- r_name = DNSName('ipa-ca') + self.domain_abs
|
|
||||||
+ r_name = DNSName(IPA_CA_RECORD) + self.domain_abs
|
|
||||||
rrsets = None
|
|
||||||
end_time = time() + CA_RECORDS_DNS_TIMEOUT
|
|
||||||
while True:
|
|
||||||
@@ -210,6 +211,7 @@ class IPASystemRecords:
|
|
||||||
|
|
||||||
for rrset in rrsets:
|
|
||||||
for rd in rrset:
|
|
||||||
+ logger.debug("Adding CA IP %s for %s", rd.to_text(), hostname)
|
|
||||||
rdataset = zone_obj.get_rdataset(
|
|
||||||
r_name, rd.rdtype, create=True)
|
|
||||||
rdataset.add(rd, ttl=self.TTL)
|
|
||||||
@@ -461,6 +463,14 @@ class IPASystemRecords:
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
+ # Remove the ipa-ca record(s). They will be reconstructed in
|
|
||||||
+ # get_base_records().
|
|
||||||
+ r_name = DNSName(IPA_CA_RECORD) + self.domain_abs
|
|
||||||
+ try:
|
|
||||||
+ self.api_instance.Command.dnsrecord_del(
|
|
||||||
+ self.domain_abs, r_name, del_all=True)
|
|
||||||
+ except errors.NotFound:
|
|
||||||
+ pass
|
|
||||||
base_zone = self.get_base_records()
|
|
||||||
for record_name, node in base_zone.items():
|
|
||||||
set_cname_template = record_name in names_requiring_cname_templates
|
|
||||||
--
|
|
||||||
2.39.1
|
|
||||||
|
|
@ -0,0 +1,55 @@
|
|||||||
|
From 5e291da42898cc646f699c21a44b03b833d346e8 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
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 <flo@redhat.com>
|
||||||
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
---
|
||||||
|
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
|
||||||
|
|
@ -0,0 +1,54 @@
|
|||||||
|
From 631dd72369385b0793e5bc0e019c088b4f1e2bb3 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
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 <flo@redhat.com>
|
||||||
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
---
|
||||||
|
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
|
||||||
|
|
@ -1,111 +0,0 @@
|
|||||||
From 0206369eec8530e96c66986c4ca501d8962193ce Mon Sep 17 00:00:00 2001
|
|
||||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
|
||||||
Date: Mon, 30 Jan 2023 14:22:30 +0200
|
|
||||||
Subject: [PATCH] ipa-kdb: PAC consistency checker needs to handle child
|
|
||||||
domains as well
|
|
||||||
|
|
||||||
When PAC check is performed, we might get a signing TGT instead of the
|
|
||||||
client DB entry. This means it is a principal from a trusted domain but
|
|
||||||
we don't know which one exactly because we only have a krbtgt for the
|
|
||||||
forest root. This happens in MIT Kerberos 1.20 or later where KDB's
|
|
||||||
issue_pac() callback never gets the original client principal directly.
|
|
||||||
|
|
||||||
Look into known child domains as well and make pass the check if both
|
|
||||||
NetBIOS name and SID correspond to one of the trusted domains under this
|
|
||||||
forest root. Move check for the SID before NetBIOS name check because we
|
|
||||||
can use SID of the domain in PAC to find out the right child domain in
|
|
||||||
our trusted domains' topology list.
|
|
||||||
|
|
||||||
Fixes: https://pagure.io/freeipa/issue/9316
|
|
||||||
|
|
||||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
|
||||||
Reviewed-By: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
|
||||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
---
|
|
||||||
daemons/ipa-kdb/ipa_kdb_mspac.c | 51 +++++++++++++++++++++------------
|
|
||||||
1 file changed, 32 insertions(+), 19 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
|
||||||
index a15050e2166f95c227d2e3c7d238e1ea2fe01235..476d1cb558a53420821ccfb1b794cb6bedce7794 100644
|
|
||||||
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
|
|
||||||
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
|
||||||
@@ -1827,11 +1827,43 @@ krb5_error_code filter_logon_info(krb5_context context,
|
|
||||||
bool result;
|
|
||||||
char *domstr = NULL;
|
|
||||||
|
|
||||||
+ ipactx = ipadb_get_context(context);
|
|
||||||
+ if (!ipactx || !ipactx->mspac) {
|
|
||||||
+ return KRB5_KDB_DBNOTINITED;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
domain = get_domain_from_realm_update(context, realm);
|
|
||||||
if (!domain) {
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ /* check exact sid */
|
|
||||||
+ result = dom_sid_check(&domain->domsid, info->info->info3.base.domain_sid, true);
|
|
||||||
+ if (!result) {
|
|
||||||
+ struct ipadb_mspac *mspac_ctx = ipactx->mspac;
|
|
||||||
+ result = FALSE;
|
|
||||||
+ /* Didn't match but perhaps the original PAC was issued by a child domain's DC? */
|
|
||||||
+ for (k = 0; k < mspac_ctx->num_trusts; k++) {
|
|
||||||
+ result = dom_sid_check(&mspac_ctx->trusts[k].domsid,
|
|
||||||
+ info->info->info3.base.domain_sid, true);
|
|
||||||
+ if (result) {
|
|
||||||
+ domain = &mspac_ctx->trusts[k];
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ if (!result) {
|
|
||||||
+ domstr = dom_sid_string(NULL, info->info->info3.base.domain_sid);
|
|
||||||
+ krb5_klog_syslog(LOG_ERR, "PAC Info mismatch: domain = %s, "
|
|
||||||
+ "expected domain SID = %s, "
|
|
||||||
+ "found domain SID = %s",
|
|
||||||
+ domain->domain_name, domain->domain_sid,
|
|
||||||
+ domstr ? domstr : "<failed to display>");
|
|
||||||
+ talloc_free(domstr);
|
|
||||||
+ return EINVAL;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* At this point we may have changed the domain we look at, */
|
|
||||||
/* check netbios/flat name */
|
|
||||||
if (strcasecmp(info->info->info3.base.logon_domain.string,
|
|
||||||
domain->flat_name) != 0) {
|
|
||||||
@@ -1843,21 +1875,6 @@ krb5_error_code filter_logon_info(krb5_context context,
|
|
||||||
return EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
- /* check exact sid */
|
|
||||||
- result = dom_sid_check(&domain->domsid, info->info->info3.base.domain_sid, true);
|
|
||||||
- if (!result) {
|
|
||||||
- domstr = dom_sid_string(NULL, info->info->info3.base.domain_sid);
|
|
||||||
- if (!domstr) {
|
|
||||||
- return EINVAL;
|
|
||||||
- }
|
|
||||||
- krb5_klog_syslog(LOG_ERR, "PAC Info mismatch: domain = %s, "
|
|
||||||
- "expected domain SID = %s, "
|
|
||||||
- "found domain SID = %s",
|
|
||||||
- domain->domain_name, domain->domain_sid, domstr);
|
|
||||||
- talloc_free(domstr);
|
|
||||||
- return EINVAL;
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
/* Check if this domain has been filtered out by the trust itself*/
|
|
||||||
if (domain->parent != NULL) {
|
|
||||||
for(k = 0; k < domain->parent->len_sid_blocklist_incoming; k++) {
|
|
||||||
@@ -1944,10 +1961,6 @@ krb5_error_code filter_logon_info(krb5_context context,
|
|
||||||
* should include different possibilities into account
|
|
||||||
* */
|
|
||||||
if (info->info->info3.sidcount != 0) {
|
|
||||||
- ipactx = ipadb_get_context(context);
|
|
||||||
- if (!ipactx || !ipactx->mspac) {
|
|
||||||
- return KRB5_KDB_DBNOTINITED;
|
|
||||||
- }
|
|
||||||
count = info->info->info3.sidcount;
|
|
||||||
i = 0;
|
|
||||||
j = 0;
|
|
||||||
--
|
|
||||||
2.39.1
|
|
||||||
|
|
@ -1,83 +0,0 @@
|
|||||||
From a6cb905de74da38d62f9c3bd7957018924282521 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Anuja More <amore@redhat.com>
|
|
||||||
Date: Mon, 30 Jan 2023 19:27:49 +0530
|
|
||||||
Subject: [PATCH] Add test for SSH with GSSAPI auth.
|
|
||||||
|
|
||||||
Added test for aduser with GSSAPI authentication.
|
|
||||||
|
|
||||||
Related : https://pagure.io/freeipa/issue/9316
|
|
||||||
|
|
||||||
Signed-off-by: Anuja More <amore@redhat.com>
|
|
||||||
Reviewed-By: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
|
||||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
---
|
|
||||||
ipatests/test_integration/test_trust.py | 46 +++++++++++++++++++++++++
|
|
||||||
1 file changed, 46 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/ipatests/test_integration/test_trust.py b/ipatests/test_integration/test_trust.py
|
|
||||||
index c4b3b99ce1abbc16817b6530939fd9bae3f9500a..0d5b71cb0277a79eed7c34eb7e3d7eb6c09faa5e 100644
|
|
||||||
--- a/ipatests/test_integration/test_trust.py
|
|
||||||
+++ b/ipatests/test_integration/test_trust.py
|
|
||||||
@@ -527,6 +527,35 @@ class TestTrust(BaseTestTrust):
|
|
||||||
.format(self.ad_domain, subordinate_suffix))
|
|
||||||
self.ad.run_command(['powershell', '-c', cmd])
|
|
||||||
|
|
||||||
+ def test_ssh_aduser(self):
|
|
||||||
+ """Test ssh with GSSAPI is working with aduser
|
|
||||||
+
|
|
||||||
+ When kerberos ticket is obtained for child domain user
|
|
||||||
+ and ssh with this ticket should be successful
|
|
||||||
+ with no password prompt.
|
|
||||||
+
|
|
||||||
+ Related : https://pagure.io/freeipa/issue/9316
|
|
||||||
+ """
|
|
||||||
+ testuser = 'testuser@{0}'.format(self.ad_domain)
|
|
||||||
+ testusersub = 'subdomaintestuser@{0}'.format(self.ad_subdomain)
|
|
||||||
+
|
|
||||||
+ def sshuser(host, user):
|
|
||||||
+ tasks.kdestroy_all(host)
|
|
||||||
+ try:
|
|
||||||
+ tasks.kinit_as_user(host, user,
|
|
||||||
+ host.config.ad_admin_password
|
|
||||||
+ )
|
|
||||||
+ ssh_cmd = "ssh -q -K -l {user} {host} hostname"
|
|
||||||
+ valid_ssh = host.run_command(
|
|
||||||
+ ssh_cmd.format(user=user, host=host.hostname)
|
|
||||||
+ )
|
|
||||||
+ assert host.hostname in valid_ssh.stdout_text
|
|
||||||
+ finally:
|
|
||||||
+ tasks.kdestroy_all(host)
|
|
||||||
+
|
|
||||||
+ sshuser(self.master, testuser)
|
|
||||||
+ sshuser(self.master, testusersub)
|
|
||||||
+
|
|
||||||
def test_remove_nonposix_trust(self):
|
|
||||||
self.remove_trust(self.ad)
|
|
||||||
tasks.unconfigure_dns_for_trust(self.master, self.ad)
|
|
||||||
@@ -785,6 +814,23 @@ class TestTrust(BaseTestTrust):
|
|
||||||
assert re.search(
|
|
||||||
testuser_regex, result.stdout_text), result.stdout_text
|
|
||||||
|
|
||||||
+ def test_ssh_adtreeuser(self):
|
|
||||||
+ testuser = 'treetestuser@{0}'.format(self.ad_treedomain)
|
|
||||||
+ self.master.run_command(["id", testuser])
|
|
||||||
+ tasks.clear_sssd_cache(self.master)
|
|
||||||
+ tasks.kdestroy_all(self.master)
|
|
||||||
+ try:
|
|
||||||
+ tasks.kinit_as_user(self.master, testuser,
|
|
||||||
+ password="Secret123456"
|
|
||||||
+ )
|
|
||||||
+ ssh_cmd = "ssh -q -K -l {user} {host} hostname"
|
|
||||||
+ valid_ssh = self.master.run_command(
|
|
||||||
+ ssh_cmd.format(user=testuser, host=self.master.hostname)
|
|
||||||
+ )
|
|
||||||
+ assert self.master.hostname in valid_ssh.stdout_text
|
|
||||||
+ finally:
|
|
||||||
+ tasks.kdestroy_all(self.master)
|
|
||||||
+
|
|
||||||
def test_remove_external_treedomain_trust(self):
|
|
||||||
self.remove_trust(self.tree_ad)
|
|
||||||
tasks.unconfigure_dns_for_trust(self.master, self.ad, self.tree_ad)
|
|
||||||
--
|
|
||||||
2.39.1
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
|||||||
|
From 1e8352486cd5f77ff79e18798f04f406baf0a9a1 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Mohammad Rizwan <myusuf@redhat.com>
|
||||||
|
Date: Wed, 14 Jun 2023 17:32:02 +0530
|
||||||
|
Subject: [PATCH] ipatests: enable firewall rule for http service on acme
|
||||||
|
client
|
||||||
|
|
||||||
|
when system hardning done i.e in case of STIG, sometimes http challanges
|
||||||
|
can't be validated by CA if port 80 is not open. This fix enable it to facilitate
|
||||||
|
the communication.
|
||||||
|
|
||||||
|
Signed-off-by: Mohammad Rizwan <myusuf@redhat.com>
|
||||||
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
|
||||||
|
---
|
||||||
|
ipatests/test_integration/test_acme.py | 4 ++++
|
||||||
|
1 file changed, 4 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/ipatests/test_integration/test_acme.py b/ipatests/test_integration/test_acme.py
|
||||||
|
index 9718c408b7f48dd78dc2abae32fb9ecb85445dfb..cca20983e65f99d5ba0bb7bc6dc2b5684a6f37d9 100644
|
||||||
|
--- a/ipatests/test_integration/test_acme.py
|
||||||
|
+++ b/ipatests/test_integration/test_acme.py
|
||||||
|
@@ -10,6 +10,7 @@ import pytest
|
||||||
|
|
||||||
|
from ipalib.constants import IPA_CA_RECORD
|
||||||
|
from ipatests.test_integration.base import IntegrationTest
|
||||||
|
+from ipatests.pytest_ipa.integration.firewall import Firewall
|
||||||
|
from ipatests.pytest_ipa.integration import tasks
|
||||||
|
from ipatests.test_integration.test_caless import CALessBase, ipa_certs_cleanup
|
||||||
|
from ipatests.test_integration.test_random_serial_numbers import (
|
||||||
|
@@ -85,6 +86,9 @@ def prepare_acme_client(master, client):
|
||||||
|
acme_host = f'{IPA_CA_RECORD}.{master.domain.name}'
|
||||||
|
acme_server = f'https://{acme_host}/acme/directory'
|
||||||
|
|
||||||
|
+ # enable firewall rule on client
|
||||||
|
+ Firewall(client).enable_services(["http", "https"])
|
||||||
|
+
|
||||||
|
# install acme client packages
|
||||||
|
if not skip_certbot_tests:
|
||||||
|
tasks.install_packages(client, ['certbot'])
|
||||||
|
--
|
||||||
|
2.41.0
|
||||||
|
|
@ -0,0 +1,79 @@
|
|||||||
|
From 387873080f1bc14aeaad89311b06dc46934be1ab Mon Sep 17 00:00:00 2001
|
||||||
|
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
Date: Wed, 19 Jul 2023 13:24:55 +0200
|
||||||
|
Subject: [PATCH] User plugin: improve error related to non existing idp
|
||||||
|
|
||||||
|
The user and stageuser commands return the following error
|
||||||
|
when the user is created/updated with a non existing idp:
|
||||||
|
$ ipa user-add testuser --first test --last user --idp dummy
|
||||||
|
ipa: ERROR: no such entry
|
||||||
|
|
||||||
|
The error is not descriptive enough and has been modified to
|
||||||
|
display instead:
|
||||||
|
$ ipa user-add testuser --first test --last user --idp dummy
|
||||||
|
ipa: ERROR: External IdP configuration dummy not found
|
||||||
|
|
||||||
|
Fixes: https://pagure.io/freeipa/issue/9416
|
||||||
|
|
||||||
|
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
---
|
||||||
|
ipaserver/plugins/baseuser.py | 6 +++++-
|
||||||
|
ipaserver/plugins/stageuser.py | 6 +++++-
|
||||||
|
ipaserver/plugins/user.py | 6 +++++-
|
||||||
|
3 files changed, 15 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/ipaserver/plugins/baseuser.py b/ipaserver/plugins/baseuser.py
|
||||||
|
index 73b76d328a88639afd40bd261c8a35f324ec865b..ba5f9b7763662b32f238c0fb0ca548ff2f07db0d 100644
|
||||||
|
--- a/ipaserver/plugins/baseuser.py
|
||||||
|
+++ b/ipaserver/plugins/baseuser.py
|
||||||
|
@@ -708,7 +708,11 @@ class baseuser_mod(LDAPUpdate):
|
||||||
|
if 'ipaidpuser' not in obj_classes:
|
||||||
|
entry_attrs['objectclass'].append('ipaidpuser')
|
||||||
|
|
||||||
|
- answer = self.api.Object['idp'].get_dn_if_exists(cl)
|
||||||
|
+ try:
|
||||||
|
+ answer = self.api.Object['idp'].get_dn_if_exists(cl)
|
||||||
|
+ except errors.NotFound:
|
||||||
|
+ reason = "External IdP configuration {} not found"
|
||||||
|
+ raise errors.NotFound(reason=_(reason).format(cl))
|
||||||
|
entry_attrs['ipaidpconfiglink'] = answer
|
||||||
|
|
||||||
|
# Note: we could have used the method add_missing_object_class
|
||||||
|
diff --git a/ipaserver/plugins/stageuser.py b/ipaserver/plugins/stageuser.py
|
||||||
|
index 51438a83a95d15fb320148d2934a52f13a38f390..852e51b0eb0d757940b84721a6f01e43c5f36dd2 100644
|
||||||
|
--- a/ipaserver/plugins/stageuser.py
|
||||||
|
+++ b/ipaserver/plugins/stageuser.py
|
||||||
|
@@ -404,7 +404,11 @@ class stageuser_add(baseuser_add):
|
||||||
|
if 'ipaidpuser' not in entry_attrs['objectclass']:
|
||||||
|
entry_attrs['objectclass'].append('ipaidpuser')
|
||||||
|
|
||||||
|
- answer = self.api.Object['idp'].get_dn_if_exists(cl)
|
||||||
|
+ try:
|
||||||
|
+ answer = self.api.Object['idp'].get_dn_if_exists(cl)
|
||||||
|
+ except errors.NotFound:
|
||||||
|
+ reason = "External IdP configuration {} not found"
|
||||||
|
+ raise errors.NotFound(reason=_(reason).format(cl))
|
||||||
|
entry_attrs['ipaidpconfiglink'] = answer
|
||||||
|
|
||||||
|
self.pre_common_callback(ldap, dn, entry_attrs, attrs_list, *keys,
|
||||||
|
diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py
|
||||||
|
index 643b44f141e3add76f95cbeec6e90fec0ad4c9ad..a337e1fc7b44ef41ad16e18bd965b7af0a767d05 100644
|
||||||
|
--- a/ipaserver/plugins/user.py
|
||||||
|
+++ b/ipaserver/plugins/user.py
|
||||||
|
@@ -638,7 +638,11 @@ class user_add(baseuser_add):
|
||||||
|
if 'ipaidpuser' not in entry_attrs['objectclass']:
|
||||||
|
entry_attrs['objectclass'].append('ipaidpuser')
|
||||||
|
|
||||||
|
- answer = self.api.Object['idp'].get_dn_if_exists(rcl)
|
||||||
|
+ try:
|
||||||
|
+ answer = self.api.Object['idp'].get_dn_if_exists(rcl)
|
||||||
|
+ except errors.NotFound:
|
||||||
|
+ reason = "External IdP configuration {} not found"
|
||||||
|
+ raise errors.NotFound(reason=_(reason).format(rcl))
|
||||||
|
entry_attrs['ipaidpconfiglink'] = answer
|
||||||
|
|
||||||
|
self.pre_common_callback(ldap, dn, entry_attrs, attrs_list, *keys,
|
||||||
|
--
|
||||||
|
2.41.0
|
||||||
|
|
@ -1,36 +0,0 @@
|
|||||||
From c411c2e7b2e400829ffac250db81609ef3c56faa Mon Sep 17 00:00:00 2001
|
|
||||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
Date: Tue, 29 Nov 2022 10:04:41 +0100
|
|
||||||
Subject: [PATCH] webui tests: fix assertion in test_subid.py
|
|
||||||
|
|
||||||
The test wants to check the error related to an
|
|
||||||
exception obtained inside a "with pytest.raises" instruction.
|
|
||||||
The object is an ExceptionInfo and offers a match method
|
|
||||||
to check the content of the string representation.
|
|
||||||
Use this match() method instead of str(excinfo) which now
|
|
||||||
returns
|
|
||||||
'<ExceptionInfo NoSuchElementException() tblen=10>'
|
|
||||||
|
|
||||||
Fixes: https://pagure.io/freeipa/issue/9282
|
|
||||||
|
|
||||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
Reviewed-By: Mohammad Rizwan Yusuf <myusuf@redhat.com>
|
|
||||||
---
|
|
||||||
ipatests/test_webui/test_subid.py | 4 ++--
|
|
||||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/ipatests/test_webui/test_subid.py b/ipatests/test_webui/test_subid.py
|
|
||||||
index 104b5692da94437880e638c0b2bc8efd41bd969e..3aaf80ac885fea08d0bac7e2f46645fe207f2cb0 100644
|
|
||||||
--- a/ipatests/test_webui/test_subid.py
|
|
||||||
+++ b/ipatests/test_webui/test_subid.py
|
|
||||||
@@ -146,5 +146,5 @@ class test_subid(UI_driver):
|
|
||||||
with pytest.raises(NoSuchElementException) as excinfo:
|
|
||||||
self.delete_record(admin_uid, table_name="ipauniqueid")
|
|
||||||
# Ensure that the exception is really related to missing remove button
|
|
||||||
- msg = "Unable to locate element: .facet-controls button[name=remove]"
|
|
||||||
- assert msg in str(excinfo)
|
|
||||||
+ msg = r"Unable to locate element: .facet-controls button\[name=remove\]"
|
|
||||||
+ assert excinfo.match(msg)
|
|
||||||
--
|
|
||||||
2.39.1
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
|||||||
From b5f2b0b1b213149b5bfe2653c9e40de98249dc73 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
Date: Tue, 10 Jan 2023 11:45:17 +0100
|
|
||||||
Subject: [PATCH] ipatests: mark test_smb as xfail
|
|
||||||
|
|
||||||
Mark the test test_smb.py::TestSMB::test_smb_service_s4u2self as xfail.
|
|
||||||
|
|
||||||
Related: https://pagure.io/freeipa/issue/9124
|
|
||||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
|
||||||
---
|
|
||||||
ipatests/test_integration/test_smb.py | 1 +
|
|
||||||
1 file changed, 1 insertion(+)
|
|
||||||
|
|
||||||
diff --git a/ipatests/test_integration/test_smb.py b/ipatests/test_integration/test_smb.py
|
|
||||||
index eb3981bddb7ca9f72a0d2cb6c46e5c73de8623ac..30f8d5901afbcda95f27cd966ac03d47205dbb26 100644
|
|
||||||
--- a/ipatests/test_integration/test_smb.py
|
|
||||||
+++ b/ipatests/test_integration/test_smb.py
|
|
||||||
@@ -349,6 +349,7 @@ class TestSMB(IntegrationTest):
|
|
||||||
@pytest.mark.skipif(
|
|
||||||
osinfo.id == 'fedora' and osinfo.version_number <= (31,),
|
|
||||||
reason='Test requires krb 1.18')
|
|
||||||
+ @pytest.mark.xfail(reason="Pagure ticket 9124", strict=True)
|
|
||||||
def test_smb_service_s4u2self(self):
|
|
||||||
"""Test S4U2Self operation by IPA service
|
|
||||||
against both AD and IPA users
|
|
||||||
--
|
|
||||||
2.39.1
|
|
||||||
|
|
@ -0,0 +1,122 @@
|
|||||||
|
From caacccc6b92c08f510fba2e31d9c56eb372abddc Mon Sep 17 00:00:00 2001
|
||||||
|
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
Date: Wed, 19 Jul 2023 13:28:43 +0200
|
||||||
|
Subject: [PATCH] xmlrpc tests: add a test for user plugin with non-existing
|
||||||
|
idp
|
||||||
|
|
||||||
|
Add new tests checking the error returned for
|
||||||
|
ipa user-add ... --idp nonexistingidp
|
||||||
|
ipa user-mod ... --idp nonexistingidp
|
||||||
|
ipa stageuser-add ... --idp nonexistingidp
|
||||||
|
ipa stageuser-mod ... --idp nonexistingidp
|
||||||
|
|
||||||
|
The expected error message is:
|
||||||
|
ipa: ERROR: External IdP configuration nonexistingidp not found
|
||||||
|
|
||||||
|
Related: https://pagure.io/freeipa/issue/9416
|
||||||
|
|
||||||
|
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
---
|
||||||
|
ipatests/test_xmlrpc/test_stageuser_plugin.py | 20 +++++++++++++++
|
||||||
|
ipatests/test_xmlrpc/test_user_plugin.py | 25 +++++++++++++++++++
|
||||||
|
2 files changed, 45 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/ipatests/test_xmlrpc/test_stageuser_plugin.py b/ipatests/test_xmlrpc/test_stageuser_plugin.py
|
||||||
|
index 394015f87f9f4bd275a15bab930e28f16b299274..9ae5561dfa4e0d54fe1231501bfea3c0ba261849 100644
|
||||||
|
--- a/ipatests/test_xmlrpc/test_stageuser_plugin.py
|
||||||
|
+++ b/ipatests/test_xmlrpc/test_stageuser_plugin.py
|
||||||
|
@@ -39,6 +39,8 @@ gid = u'456'
|
||||||
|
invalidrealm1 = u'suser1@NOTFOUND.ORG'
|
||||||
|
invalidrealm2 = u'suser1@BAD@NOTFOUND.ORG'
|
||||||
|
|
||||||
|
+nonexistentidp = 'IdPDoesNotExist'
|
||||||
|
+
|
||||||
|
invaliduser1 = u'+tuser1'
|
||||||
|
invaliduser2 = u'tuser1234567890123456789012345678901234567890'
|
||||||
|
|
||||||
|
@@ -431,6 +433,15 @@ class TestCreateInvalidAttributes(XMLRPC_test):
|
||||||
|
invalidrealm2))):
|
||||||
|
command()
|
||||||
|
|
||||||
|
+ def test_create_invalid_idp(self, stageduser):
|
||||||
|
+ stageduser.ensure_missing()
|
||||||
|
+ command = stageduser.make_create_command(
|
||||||
|
+ options={u'ipaidpconfiglink': nonexistentidp})
|
||||||
|
+ with raises_exact(errors.NotFound(
|
||||||
|
+ reason="External IdP configuration {} not found".format(
|
||||||
|
+ nonexistentidp))):
|
||||||
|
+ command()
|
||||||
|
+
|
||||||
|
|
||||||
|
@pytest.mark.tier1
|
||||||
|
class TestUpdateInvalidAttributes(XMLRPC_test):
|
||||||
|
@@ -466,6 +477,15 @@ class TestUpdateInvalidAttributes(XMLRPC_test):
|
||||||
|
message=u'invalid \'gidnumber\': must be at least 1')):
|
||||||
|
command()
|
||||||
|
|
||||||
|
+ def test_update_invalididp(self, stageduser):
|
||||||
|
+ stageduser.ensure_exists()
|
||||||
|
+ command = stageduser.make_update_command(
|
||||||
|
+ updates={u'ipaidpconfiglink': nonexistentidp})
|
||||||
|
+ with raises_exact(errors.NotFound(
|
||||||
|
+ reason="External IdP configuration {} not found".format(
|
||||||
|
+ nonexistentidp))):
|
||||||
|
+ command()
|
||||||
|
+
|
||||||
|
|
||||||
|
@pytest.mark.tier1
|
||||||
|
class TestActive(XMLRPC_test):
|
||||||
|
diff --git a/ipatests/test_xmlrpc/test_user_plugin.py b/ipatests/test_xmlrpc/test_user_plugin.py
|
||||||
|
index 8ac19a4f9ce4f341838282ecd3ed1bb491ac7004..baa28672e7552140a703ecdfa5772b445298cb37 100644
|
||||||
|
--- a/ipatests/test_xmlrpc/test_user_plugin.py
|
||||||
|
+++ b/ipatests/test_xmlrpc/test_user_plugin.py
|
||||||
|
@@ -86,6 +86,8 @@ expired_expiration_string = "1991-12-07T19:54:13Z"
|
||||||
|
# Date in ISO format (2013-12-10T12:00:00)
|
||||||
|
isodate_re = re.compile(r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$')
|
||||||
|
|
||||||
|
+nonexistentidp = 'IdPDoesNotExist'
|
||||||
|
+
|
||||||
|
|
||||||
|
@pytest.fixture(scope='class')
|
||||||
|
def user_min(request, xmlrpc_setup):
|
||||||
|
@@ -542,6 +544,18 @@ class TestUpdate(XMLRPC_test):
|
||||||
|
command()
|
||||||
|
user.delete()
|
||||||
|
|
||||||
|
+ def test_update_invalid_idp(self, user):
|
||||||
|
+ """ Test user-mod --idp with a non-existent idp """
|
||||||
|
+ user.ensure_exists()
|
||||||
|
+ command = user.make_update_command(
|
||||||
|
+ updates=dict(ipaidpconfiglink=nonexistentidp)
|
||||||
|
+ )
|
||||||
|
+ with raises_exact(errors.NotFound(
|
||||||
|
+ reason="External IdP configuration {} not found".format(
|
||||||
|
+ nonexistentidp)
|
||||||
|
+ )):
|
||||||
|
+ command()
|
||||||
|
+
|
||||||
|
|
||||||
|
@pytest.mark.tier1
|
||||||
|
class TestCreate(XMLRPC_test):
|
||||||
|
@@ -770,6 +784,17 @@ class TestCreate(XMLRPC_test):
|
||||||
|
user_radius.check_create(result)
|
||||||
|
user_radius.delete()
|
||||||
|
|
||||||
|
+ def test_create_with_invalididp(self):
|
||||||
|
+ testuser = UserTracker(
|
||||||
|
+ name='idpuser', givenname='idp', sn='user',
|
||||||
|
+ ipaidpconfiglink=nonexistentidp
|
||||||
|
+ )
|
||||||
|
+ with raises_exact(errors.NotFound(
|
||||||
|
+ reason="External IdP configuration {} not found".format(
|
||||||
|
+ nonexistentidp)
|
||||||
|
+ )):
|
||||||
|
+ testuser.create()
|
||||||
|
+
|
||||||
|
|
||||||
|
@pytest.mark.tier1
|
||||||
|
class TestUserWithGroup(XMLRPC_test):
|
||||||
|
--
|
||||||
|
2.41.0
|
||||||
|
|
117
SOURCES/0017-Fix-memory-leak-in-the-OTP-last-token-plugin.patch
Normal file
117
SOURCES/0017-Fix-memory-leak-in-the-OTP-last-token-plugin.patch
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
From 421e8e9ac886c50b4bb463a62b8ad5de8da94f31 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
Date: Mon, 26 Jun 2023 13:06:51 -0400
|
||||||
|
Subject: [PATCH] Fix memory leak in the OTP last token plugin
|
||||||
|
|
||||||
|
Three memory leaks are addressed:
|
||||||
|
|
||||||
|
1. String values retrieved from the pblock need to be manually
|
||||||
|
freed.
|
||||||
|
|
||||||
|
2. The list of objectclasses retreived from the pblock need to be
|
||||||
|
freed.
|
||||||
|
|
||||||
|
3. Internal search results need to be freed.
|
||||||
|
|
||||||
|
Fixes: https://pagure.io/freeipa/issue/9403
|
||||||
|
|
||||||
|
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
Reviewed-By: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||||
|
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||||
|
---
|
||||||
|
.../ipa-otp-lasttoken/ipa_otp_lasttoken.c | 38 +++++++++++++------
|
||||||
|
daemons/ipa-slapi-plugins/libotp/otp_token.c | 1 +
|
||||||
|
2 files changed, 27 insertions(+), 12 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c
|
||||||
|
index b7a2ba7f012fdbf90284ee6605788e196aa4793b..11106b239f9de9074125979cfae7c02e434936e1 100644
|
||||||
|
--- a/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c
|
||||||
|
+++ b/daemons/ipa-slapi-plugins/ipa-otp-lasttoken/ipa_otp_lasttoken.c
|
||||||
|
@@ -54,7 +54,7 @@ void *ipa_otp_lasttoken_plugin_id;
|
||||||
|
|
||||||
|
static bool entry_is_token(Slapi_Entry *entry)
|
||||||
|
{
|
||||||
|
- char **ocls;
|
||||||
|
+ char **ocls = NULL;
|
||||||
|
|
||||||
|
ocls = slapi_entry_attr_get_charray(entry, SLAPI_ATTR_OBJECTCLASS);
|
||||||
|
for (size_t i = 0; ocls != NULL && ocls[i] != NULL; i++) {
|
||||||
|
@@ -64,6 +64,7 @@ static bool entry_is_token(Slapi_Entry *entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ slapi_ch_array_free(ocls);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -138,7 +139,8 @@ static bool is_pwd_enabled(const char *user_dn)
|
||||||
|
static bool is_allowed(Slapi_PBlock *pb, Slapi_Entry *entry)
|
||||||
|
{
|
||||||
|
Slapi_DN *target_sdn = NULL;
|
||||||
|
- const char *bind_dn;
|
||||||
|
+ char *bind_dn;
|
||||||
|
+ bool rv = false;
|
||||||
|
|
||||||
|
/* Ignore internal operations. */
|
||||||
|
if (slapi_op_internal(pb))
|
||||||
|
@@ -147,23 +149,35 @@ static bool is_allowed(Slapi_PBlock *pb, Slapi_Entry *entry)
|
||||||
|
/* Load parameters. */
|
||||||
|
(void) slapi_pblock_get(pb, SLAPI_TARGET_SDN, &target_sdn);
|
||||||
|
(void) slapi_pblock_get(pb, SLAPI_CONN_DN, &bind_dn);
|
||||||
|
- if (target_sdn == NULL || bind_dn == NULL) {
|
||||||
|
- LOG_FATAL("Missing parameters!\n");
|
||||||
|
- return false;
|
||||||
|
+ if (bind_dn == NULL) {
|
||||||
|
+ LOG_FATAL("bind_dn parameter missing!\n");
|
||||||
|
+ goto done;
|
||||||
|
+ }
|
||||||
|
+ if (target_sdn == NULL) {
|
||||||
|
+ LOG_FATAL("target_sdn parameter missing!\n");
|
||||||
|
+ goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry != NULL
|
||||||
|
? !entry_is_token(entry)
|
||||||
|
- : !sdn_in_otp_container(target_sdn))
|
||||||
|
- return true;
|
||||||
|
+ : !sdn_in_otp_container(target_sdn)) {
|
||||||
|
+ rv = true;
|
||||||
|
+ goto done;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- if (!sdn_is_only_enabled_token(target_sdn, bind_dn))
|
||||||
|
- return true;
|
||||||
|
+ if (!sdn_is_only_enabled_token(target_sdn, bind_dn)) {
|
||||||
|
+ rv = true;
|
||||||
|
+ goto done;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- if (is_pwd_enabled(bind_dn))
|
||||||
|
- return true;
|
||||||
|
+ if (is_pwd_enabled(bind_dn)) {
|
||||||
|
+ rv = true;
|
||||||
|
+ goto done;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
- return false;
|
||||||
|
+done:
|
||||||
|
+ slapi_ch_free_string(&bind_dn);
|
||||||
|
+ return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int send_error(Slapi_PBlock *pb, int rc, const char *errstr)
|
||||||
|
diff --git a/daemons/ipa-slapi-plugins/libotp/otp_token.c b/daemons/ipa-slapi-plugins/libotp/otp_token.c
|
||||||
|
index a3cbfb0621c071f8addb29f7ce02f870a807c61d..4be4ede07cbbd0d26bcc9952ef4d84d777076ae7 100644
|
||||||
|
--- a/daemons/ipa-slapi-plugins/libotp/otp_token.c
|
||||||
|
+++ b/daemons/ipa-slapi-plugins/libotp/otp_token.c
|
||||||
|
@@ -398,6 +398,7 @@ static struct otp_token **find(const struct otp_config *cfg, const char *user_dn
|
||||||
|
}
|
||||||
|
|
||||||
|
error:
|
||||||
|
+ slapi_free_search_results_internal(pb);
|
||||||
|
slapi_pblock_destroy(pb);
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
--
|
||||||
|
2.41.0
|
||||||
|
|
@ -1,43 +0,0 @@
|
|||||||
From 36cba23f3f671886f5e7fa310c25a6e500c76e0b Mon Sep 17 00:00:00 2001
|
|
||||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
Date: Mon, 16 Jan 2023 09:31:57 +0100
|
|
||||||
Subject: [PATCH] Tests: force key type in ACME tests
|
|
||||||
|
|
||||||
PKI can issue ACME certs only when the key type is rsa.
|
|
||||||
|
|
||||||
With version 2.0.0, certbot defaults to ecdsa key type,
|
|
||||||
and this causes test failures.
|
|
||||||
For now, force rsa when requesting an ACME certificate.
|
|
||||||
This change can be reverted when PKI fixes the issue
|
|
||||||
on their side (https://github.com/dogtagpki/pki/issues/4273)
|
|
||||||
|
|
||||||
Related: https://pagure.io/freeipa/issue/9298
|
|
||||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
---
|
|
||||||
ipatests/test_integration/test_acme.py | 2 ++
|
|
||||||
1 file changed, 2 insertions(+)
|
|
||||||
|
|
||||||
diff --git a/ipatests/test_integration/test_acme.py b/ipatests/test_integration/test_acme.py
|
|
||||||
index a30f2fc756783c0a5c28ecf32c1e40f422c47a19..15d7543cfb0fa0fcb921166f7cd8f13d0535a41d 100644
|
|
||||||
--- a/ipatests/test_integration/test_acme.py
|
|
||||||
+++ b/ipatests/test_integration/test_acme.py
|
|
||||||
@@ -131,6 +131,7 @@ def certbot_standalone_cert(host, acme_server):
|
|
||||||
'certonly',
|
|
||||||
'--domain', host.hostname,
|
|
||||||
'--standalone',
|
|
||||||
+ '--key-type', 'rsa',
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
@@ -305,6 +306,7 @@ class TestACME(CALessBase):
|
|
||||||
'--manual-public-ip-logging-ok',
|
|
||||||
'--manual-auth-hook', CERTBOT_DNS_IPA_SCRIPT,
|
|
||||||
'--manual-cleanup-hook', CERTBOT_DNS_IPA_SCRIPT,
|
|
||||||
+ '--key-type', 'rsa',
|
|
||||||
])
|
|
||||||
|
|
||||||
##############
|
|
||||||
--
|
|
||||||
2.39.1
|
|
||||||
|
|
136
SOURCES/0018-Prevent-the-admin-user-from-being-deleted.patch
Normal file
136
SOURCES/0018-Prevent-the-admin-user-from-being-deleted.patch
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
From 4b02322fc786ee9caaa0380659507a2cec0d4101 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
Date: Thu, 25 May 2023 18:24:29 -0400
|
||||||
|
Subject: [PATCH] Prevent the admin user from being deleted
|
||||||
|
|
||||||
|
admin is required for trust operations
|
||||||
|
|
||||||
|
Note that testing for removing the last member is now
|
||||||
|
irrelevant because admin must always exist so the test
|
||||||
|
for it was removed, but the code check remains. It is done
|
||||||
|
after the protected member check.
|
||||||
|
|
||||||
|
Fixes: https://pagure.io/freeipa/issue/8878
|
||||||
|
|
||||||
|
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||||
|
---
|
||||||
|
ipaserver/plugins/user.py | 19 +++++++++--
|
||||||
|
ipatests/test_xmlrpc/test_user_plugin.py | 40 ++++++++++++------------
|
||||||
|
2 files changed, 37 insertions(+), 22 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py
|
||||||
|
index a337e1fc7b44ef41ad16e18bd965b7af0a767d05..6f5e34917e1b838a463dee146a4e9390f20c130a 100644
|
||||||
|
--- a/ipaserver/plugins/user.py
|
||||||
|
+++ b/ipaserver/plugins/user.py
|
||||||
|
@@ -138,14 +138,23 @@ MEMBEROF_ADMINS = "(memberOf={})".format(
|
||||||
|
)
|
||||||
|
|
||||||
|
NOT_MEMBEROF_ADMINS = '(!{})'.format(MEMBEROF_ADMINS)
|
||||||
|
+PROTECTED_USERS = ('admin',)
|
||||||
|
|
||||||
|
|
||||||
|
def check_protected_member(user, protected_group_name=u'admins'):
|
||||||
|
'''
|
||||||
|
- Ensure the last enabled member of a protected group cannot be deleted or
|
||||||
|
- disabled by raising LastMemberError.
|
||||||
|
+ Ensure admin and the last enabled member of a protected group cannot
|
||||||
|
+ be deleted or disabled by raising ProtectedEntryError or
|
||||||
|
+ LastMemberError as appropriate.
|
||||||
|
'''
|
||||||
|
|
||||||
|
+ if user in PROTECTED_USERS:
|
||||||
|
+ raise errors.ProtectedEntryError(
|
||||||
|
+ label=_("user"),
|
||||||
|
+ key=user,
|
||||||
|
+ reason=_("privileged user"),
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
# Get all users in the protected group
|
||||||
|
result = api.Command.user_find(in_group=protected_group_name)
|
||||||
|
|
||||||
|
@@ -868,6 +877,12 @@ class user_mod(baseuser_mod):
|
||||||
|
|
||||||
|
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
|
||||||
|
dn, oc = self.obj.get_either_dn(*keys, **options)
|
||||||
|
+ if options.get('rename') and keys[-1] in PROTECTED_USERS:
|
||||||
|
+ raise errors.ProtectedEntryError(
|
||||||
|
+ label=_("user"),
|
||||||
|
+ key=keys[-1],
|
||||||
|
+ reason=_("privileged user"),
|
||||||
|
+ )
|
||||||
|
if 'objectclass' not in entry_attrs and 'rename' not in options:
|
||||||
|
entry_attrs.update({'objectclass': oc})
|
||||||
|
self.pre_common_callback(ldap, dn, entry_attrs, attrs_list, *keys,
|
||||||
|
diff --git a/ipatests/test_xmlrpc/test_user_plugin.py b/ipatests/test_xmlrpc/test_user_plugin.py
|
||||||
|
index baa28672e7552140a703ecdfa5772b445298cb37..df105a23529b29944411a6418e5db55d56e2c72a 100644
|
||||||
|
--- a/ipatests/test_xmlrpc/test_user_plugin.py
|
||||||
|
+++ b/ipatests/test_xmlrpc/test_user_plugin.py
|
||||||
|
@@ -978,22 +978,32 @@ class TestManagers(XMLRPC_test):
|
||||||
|
|
||||||
|
@pytest.mark.tier1
|
||||||
|
class TestAdmins(XMLRPC_test):
|
||||||
|
- def test_remove_original_admin(self):
|
||||||
|
- """ Try to remove the only admin """
|
||||||
|
+ def test_delete_admin(self):
|
||||||
|
+ """ Try to delete the protected admin user """
|
||||||
|
tracker = Tracker()
|
||||||
|
- command = tracker.make_command('user_del', [admin1])
|
||||||
|
+ command = tracker.make_command('user_del', admin1)
|
||||||
|
|
||||||
|
- with raises_exact(errors.LastMemberError(
|
||||||
|
- key=admin1, label=u'group', container=admin_group)):
|
||||||
|
+ with raises_exact(errors.ProtectedEntryError(label=u'user',
|
||||||
|
+ key=admin1, reason='privileged user')):
|
||||||
|
+ command()
|
||||||
|
+
|
||||||
|
+ def test_rename_admin(self):
|
||||||
|
+ """ Try to rename the admin user """
|
||||||
|
+ tracker = Tracker()
|
||||||
|
+ command = tracker.make_command('user_mod', admin1,
|
||||||
|
+ **dict(rename=u'newadmin'))
|
||||||
|
+
|
||||||
|
+ with raises_exact(errors.ProtectedEntryError(label=u'user',
|
||||||
|
+ key=admin1, reason='privileged user')):
|
||||||
|
command()
|
||||||
|
|
||||||
|
def test_disable_original_admin(self):
|
||||||
|
- """ Try to disable the only admin """
|
||||||
|
+ """ Try to disable the original admin """
|
||||||
|
tracker = Tracker()
|
||||||
|
command = tracker.make_command('user_disable', admin1)
|
||||||
|
|
||||||
|
- with raises_exact(errors.LastMemberError(
|
||||||
|
- key=admin1, label=u'group', container=admin_group)):
|
||||||
|
+ with raises_exact(errors.ProtectedEntryError(label=u'user',
|
||||||
|
+ key=admin1, reason='privileged user')):
|
||||||
|
command()
|
||||||
|
|
||||||
|
def test_create_admin2(self, admin2):
|
||||||
|
@@ -1011,21 +1021,11 @@ class TestAdmins(XMLRPC_test):
|
||||||
|
admin2.disable()
|
||||||
|
tracker = Tracker()
|
||||||
|
|
||||||
|
- with raises_exact(errors.LastMemberError(
|
||||||
|
- key=admin1, label=u'group', container=admin_group)):
|
||||||
|
+ with raises_exact(errors.ProtectedEntryError(label=u'user',
|
||||||
|
+ key=admin1, reason='privileged user')):
|
||||||
|
tracker.run_command('user_disable', admin1)
|
||||||
|
- with raises_exact(errors.LastMemberError(
|
||||||
|
- key=admin1, label=u'group', container=admin_group)):
|
||||||
|
- tracker.run_command('user_del', admin1)
|
||||||
|
admin2.delete()
|
||||||
|
|
||||||
|
- with raises_exact(errors.LastMemberError(
|
||||||
|
- key=admin1, label=u'group', container=admin_group)):
|
||||||
|
- tracker.run_command('user_disable', admin1)
|
||||||
|
- with raises_exact(errors.LastMemberError(
|
||||||
|
- key=admin1, label=u'group', container=admin_group)):
|
||||||
|
- tracker.run_command('user_del', admin1)
|
||||||
|
-
|
||||||
|
|
||||||
|
@pytest.mark.tier1
|
||||||
|
class TestPreferredLanguages(XMLRPC_test):
|
||||||
|
--
|
||||||
|
2.41.0
|
||||||
|
|
@ -1,36 +0,0 @@
|
|||||||
From ff31b0c40cc5e046f839b98b80bd16bb649205ac Mon Sep 17 00:00:00 2001
|
|
||||||
From: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
Date: Mon, 30 Jan 2023 11:54:36 -0500
|
|
||||||
Subject: [PATCH] tests: Add ipa_ca_name checking to DNS system records
|
|
||||||
|
|
||||||
freeipa-healthcheck 0.12 includes a SUCCESS message if the
|
|
||||||
ipa-ca records are as expected so a user will know they
|
|
||||||
were checked. For that version and beyond test that it
|
|
||||||
is included.
|
|
||||||
|
|
||||||
Related: https://pagure.io/freeipa/issue/9291
|
|
||||||
|
|
||||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
---
|
|
||||||
ipatests/test_integration/test_ipahealthcheck.py | 4 +++-
|
|
||||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
|
||||||
|
|
||||||
diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py
|
|
||||||
index 49a5779307ef05617fe9ae200f7149d120977355..94b0db0b7869e722955e232e1dddb26a2dc3d41e 100644
|
|
||||||
--- a/ipatests/test_integration/test_ipahealthcheck.py
|
|
||||||
+++ b/ipatests/test_integration/test_ipahealthcheck.py
|
|
||||||
@@ -810,7 +810,9 @@ class TestIpaHealthCheck(IntegrationTest):
|
|
||||||
+ [str(ip) for ip in resolve_ip_addresses_nss(h.external_hostname)]
|
|
||||||
]
|
|
||||||
SYSTEM_RECORDS.append(f'"{self.master.domain.realm.upper()}"')
|
|
||||||
-
|
|
||||||
+ version = tasks.get_healthcheck_version(self.master)
|
|
||||||
+ if parse_version(version) >= parse_version("0.12"):
|
|
||||||
+ SYSTEM_RECORDS.append('ipa_ca_check')
|
|
||||||
|
|
||||||
returncode, data = run_healthcheck(
|
|
||||||
self.master,
|
|
||||||
--
|
|
||||||
2.39.1
|
|
||||||
|
|
@ -0,0 +1,87 @@
|
|||||||
|
From fd32e6a3d95f28d2d11d41ee5dabb0d563cb5d51 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Julien Rische <jrische@redhat.com>
|
||||||
|
Date: Mon, 31 Jul 2023 11:26:43 +0200
|
||||||
|
Subject: [PATCH] ipa-kdb: fix error handling of is_master_host()
|
||||||
|
|
||||||
|
Adding proper error handling to the is_master_host() function to allow
|
||||||
|
it to make the difference between the absence of a master host object
|
||||||
|
and a connection failure. This will keep the krb5kdc daemon from
|
||||||
|
continuing to run with a NULL LDAP context.
|
||||||
|
|
||||||
|
Fixes: https://pagure.io/freeipa/issue/9422
|
||||||
|
|
||||||
|
Signed-off-by: Julien Rische <jrische@redhat.com>
|
||||||
|
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||||
|
---
|
||||||
|
daemons/ipa-kdb/ipa_kdb_mspac.c | 41 +++++++++++++++++++--------------
|
||||||
|
1 file changed, 24 insertions(+), 17 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||||
|
index 83b507cb422c735f933edaebfc7b903b8fa908e4..1558e2bead288d9d00014e9b3b059934e80b54e4 100644
|
||||||
|
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||||
|
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||||
|
@@ -401,27 +401,29 @@ static krb5_error_code ipadb_add_asserted_identity(struct ipadb_context *ipactx,
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static bool is_master_host(struct ipadb_context *ipactx, const char *fqdn)
|
||||||
|
+static krb5_error_code
|
||||||
|
+is_master_host(struct ipadb_context *ipactx, const char *fqdn, bool *result)
|
||||||
|
{
|
||||||
|
- int ret;
|
||||||
|
+ int err;
|
||||||
|
char *master_host_base = NULL;
|
||||||
|
- LDAPMessage *result = NULL;
|
||||||
|
- krb5_error_code err;
|
||||||
|
+ LDAPMessage *ldap_res = NULL;
|
||||||
|
|
||||||
|
- ret = asprintf(&master_host_base, "cn=%s,cn=masters,cn=ipa,cn=etc,%s",
|
||||||
|
+ err = asprintf(&master_host_base, "cn=%s,cn=masters,cn=ipa,cn=etc,%s",
|
||||||
|
fqdn, ipactx->base);
|
||||||
|
- if (ret == -1) {
|
||||||
|
- return false;
|
||||||
|
- }
|
||||||
|
+ if (err == -1)
|
||||||
|
+ return ENOMEM;
|
||||||
|
+
|
||||||
|
err = ipadb_simple_search(ipactx, master_host_base, LDAP_SCOPE_BASE,
|
||||||
|
- NULL, NULL, &result);
|
||||||
|
+ NULL, NULL, &ldap_res);
|
||||||
|
free(master_host_base);
|
||||||
|
- ldap_msgfree(result);
|
||||||
|
- if (err == 0) {
|
||||||
|
- return true;
|
||||||
|
- }
|
||||||
|
+ ldap_msgfree(ldap_res);
|
||||||
|
+ if (err != KRB5_KDB_NOENTRY && err != 0)
|
||||||
|
+ return err;
|
||||||
|
+
|
||||||
|
+ if (result)
|
||||||
|
+ *result = err != KRB5_KDB_NOENTRY;
|
||||||
|
|
||||||
|
- return false;
|
||||||
|
+ return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
|
||||||
|
@@ -692,9 +694,14 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
|
||||||
|
if ((is_host || is_service)) {
|
||||||
|
/* it is either host or service, so get the hostname first */
|
||||||
|
char *sep = strchr(info3->base.account_name.string, '/');
|
||||||
|
- bool is_master = is_master_host(
|
||||||
|
- ipactx,
|
||||||
|
- sep ? sep + 1 : info3->base.account_name.string);
|
||||||
|
+ bool is_master;
|
||||||
|
+
|
||||||
|
+ ret = is_master_host(ipactx,
|
||||||
|
+ sep ? sep + 1 : info3->base.account_name.string,
|
||||||
|
+ &is_master);
|
||||||
|
+ if (ret)
|
||||||
|
+ return ret;
|
||||||
|
+
|
||||||
|
if (is_master) {
|
||||||
|
/* Well known RID of domain controllers group */
|
||||||
|
if (info3->base.rid == 0) {
|
||||||
|
--
|
||||||
|
2.41.0
|
||||||
|
|
@ -1,53 +0,0 @@
|
|||||||
From 6ca119686aadfa72c0474f72758b63cd671952d4 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
Date: Mon, 30 Jan 2023 12:00:03 -0500
|
|
||||||
Subject: [PATCH] tests: Add new ipa-ca error messages to
|
|
||||||
IPADNSSystemRecordsCheck
|
|
||||||
|
|
||||||
freeipa-healthcheck changed some messages related to ipa-ca
|
|
||||||
DNS record validation in IPADNSSystemRecordsCheck. Include support
|
|
||||||
for it and retain backwards compatibility.
|
|
||||||
|
|
||||||
Fixes: https://pagure.io/freeipa/issue/9291
|
|
||||||
|
|
||||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
---
|
|
||||||
.../test_integration/test_ipahealthcheck.py | 21 +++++++++++++------
|
|
||||||
1 file changed, 15 insertions(+), 6 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py
|
|
||||||
index 94b0db0b7869e722955e232e1dddb26a2dc3d41e..47f64f2cb36904ef61211423de7cf33d21a199c3 100644
|
|
||||||
--- a/ipatests/test_integration/test_ipahealthcheck.py
|
|
||||||
+++ b/ipatests/test_integration/test_ipahealthcheck.py
|
|
||||||
@@ -1614,12 +1614,21 @@ class TestIpaHealthCheckWithoutDNS(IntegrationTest):
|
|
||||||
Test checks the result of IPADNSSystemRecordsCheck
|
|
||||||
when ipa-server is configured without DNS.
|
|
||||||
"""
|
|
||||||
- expected_msgs = {
|
|
||||||
- "Expected SRV record missing",
|
|
||||||
- "Got {count} ipa-ca A records, expected {expected}",
|
|
||||||
- "Got {count} ipa-ca AAAA records, expected {expected}",
|
|
||||||
- "Expected URI record missing",
|
|
||||||
- }
|
|
||||||
+ version = tasks.get_healthcheck_version(self.master)
|
|
||||||
+ if (parse_version(version) < parse_version('0.12')):
|
|
||||||
+ expected_msgs = {
|
|
||||||
+ "Expected SRV record missing",
|
|
||||||
+ "Got {count} ipa-ca A records, expected {expected}",
|
|
||||||
+ "Got {count} ipa-ca AAAA records, expected {expected}",
|
|
||||||
+ "Expected URI record missing",
|
|
||||||
+ }
|
|
||||||
+ else:
|
|
||||||
+ expected_msgs = {
|
|
||||||
+ "Expected SRV record missing",
|
|
||||||
+ "Unexpected ipa-ca address {ipaddr}",
|
|
||||||
+ "expected ipa-ca to contain {ipaddr} for {server}",
|
|
||||||
+ "Expected URI record missing",
|
|
||||||
+ }
|
|
||||||
|
|
||||||
tasks.install_packages(self.master, HEALTHCHECK_PKG)
|
|
||||||
returncode, data = run_healthcheck(
|
|
||||||
--
|
|
||||||
2.39.1
|
|
||||||
|
|
@ -1,445 +0,0 @@
|
|||||||
From 0f77b359e241fc4055fb8d785e18f96338451ebf Mon Sep 17 00:00:00 2001
|
|
||||||
From: Mohammad Rizwan <myusuf@redhat.com>
|
|
||||||
Date: Mon, 6 Feb 2023 15:31:27 +0530
|
|
||||||
Subject: [PATCH] ipatests: tests for certificate pruning
|
|
||||||
|
|
||||||
1. Test to prune the expired certificate by manual run
|
|
||||||
2. Test to prune expired certificate by cron job
|
|
||||||
3. Test to prune expired certificate with retention unit option
|
|
||||||
4. Test to prune expired certificate with search size limit option
|
|
||||||
5. Test to check config-show command shows set param
|
|
||||||
6. Test prune command shows proper status after disabling the pruning
|
|
||||||
|
|
||||||
related: https://pagure.io/freeipa/issue/9294
|
|
||||||
|
|
||||||
Signed-off-by: Mohammad Rizwan <myusuf@redhat.com>
|
|
||||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
|
||||||
---
|
|
||||||
ipatests/test_integration/test_acme.py | 306 +++++++++++++++++++++----
|
|
||||||
1 file changed, 260 insertions(+), 46 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/ipatests/test_integration/test_acme.py b/ipatests/test_integration/test_acme.py
|
|
||||||
index 5ceba05976059de69414a79634d98045c3ab68bb..1334be52f4530dd8b2a4207744146cd0eb5477a3 100644
|
|
||||||
--- a/ipatests/test_integration/test_acme.py
|
|
||||||
+++ b/ipatests/test_integration/test_acme.py
|
|
||||||
@@ -122,21 +122,23 @@ def certbot_register(host, acme_server):
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
-def certbot_standalone_cert(host, acme_server):
|
|
||||||
+def certbot_standalone_cert(host, acme_server, no_of_cert=1):
|
|
||||||
"""method to issue a certbot's certonly standalone cert"""
|
|
||||||
# Get a cert from ACME service using HTTP challenge and Certbot's
|
|
||||||
# standalone HTTP server mode
|
|
||||||
host.run_command(['systemctl', 'stop', 'httpd'])
|
|
||||||
- host.run_command(
|
|
||||||
- [
|
|
||||||
- 'certbot',
|
|
||||||
- '--server', acme_server,
|
|
||||||
- 'certonly',
|
|
||||||
- '--domain', host.hostname,
|
|
||||||
- '--standalone',
|
|
||||||
- '--key-type', 'rsa',
|
|
||||||
- ]
|
|
||||||
- )
|
|
||||||
+ for _i in range(0, no_of_cert):
|
|
||||||
+ host.run_command(
|
|
||||||
+ [
|
|
||||||
+ 'certbot',
|
|
||||||
+ '--server', acme_server,
|
|
||||||
+ 'certonly',
|
|
||||||
+ '--domain', host.hostname,
|
|
||||||
+ '--standalone',
|
|
||||||
+ '--key-type', 'rsa',
|
|
||||||
+ '--force-renewal'
|
|
||||||
+ ]
|
|
||||||
+ )
|
|
||||||
|
|
||||||
|
|
||||||
class TestACME(CALessBase):
|
|
||||||
@@ -573,43 +575,41 @@ class TestACMEwithExternalCA(TestACME):
|
|
||||||
tasks.install_replica(cls.master, cls.replicas[0])
|
|
||||||
|
|
||||||
|
|
||||||
-class TestACMERenew(IntegrationTest):
|
|
||||||
-
|
|
||||||
- num_clients = 1
|
|
||||||
+@pytest.fixture
|
|
||||||
+def issue_and_expire_acme_cert():
|
|
||||||
+ """Fixture to expire cert by moving date past expiry of acme cert"""
|
|
||||||
+ hosts = []
|
|
||||||
|
|
||||||
- @classmethod
|
|
||||||
- def install(cls, mh):
|
|
||||||
-
|
|
||||||
- # install packages before client install in case of IPA DNS problems
|
|
||||||
- cls.acme_server = prepare_acme_client(cls.master, cls.clients[0])
|
|
||||||
+ def _issue_and_expire_acme_cert(
|
|
||||||
+ master, client,
|
|
||||||
+ acme_server_url, no_of_cert=1
|
|
||||||
+ ):
|
|
||||||
|
|
||||||
- tasks.install_master(cls.master, setup_dns=True)
|
|
||||||
- tasks.install_client(cls.master, cls.clients[0])
|
|
||||||
+ hosts.append(master)
|
|
||||||
+ hosts.append(client)
|
|
||||||
|
|
||||||
- @pytest.fixture
|
|
||||||
- def issue_and_expire_cert(self):
|
|
||||||
- """Fixture to expire cert by moving date past expiry of acme cert"""
|
|
||||||
# enable the ACME service on master
|
|
||||||
- self.master.run_command(['ipa-acme-manage', 'enable'])
|
|
||||||
+ master.run_command(['ipa-acme-manage', 'enable'])
|
|
||||||
|
|
||||||
# register the account with certbot
|
|
||||||
- certbot_register(self.clients[0], self.acme_server)
|
|
||||||
+ certbot_register(client, acme_server_url)
|
|
||||||
|
|
||||||
# request a standalone acme cert
|
|
||||||
- certbot_standalone_cert(self.clients[0], self.acme_server)
|
|
||||||
+ certbot_standalone_cert(client, acme_server_url, no_of_cert)
|
|
||||||
|
|
||||||
# move system date to expire acme cert
|
|
||||||
- for host in self.clients[0], self.master:
|
|
||||||
+ for host in hosts:
|
|
||||||
tasks.kdestroy_all(host)
|
|
||||||
tasks.move_date(host, 'stop', '+90days')
|
|
||||||
|
|
||||||
+ time.sleep(10)
|
|
||||||
tasks.get_kdcinfo(host)
|
|
||||||
# Note raiseonerr=False:
|
|
||||||
# the assert is located after kdcinfo retrieval.
|
|
||||||
- result = host.run_command(
|
|
||||||
+ result = master.run_command(
|
|
||||||
"KRB5_TRACE=/dev/stdout kinit admin",
|
|
||||||
stdin_text='{0}\n{0}\n{0}\n'.format(
|
|
||||||
- self.clients[0].config.admin_password
|
|
||||||
+ master.config.admin_password
|
|
||||||
),
|
|
||||||
raiseonerr=False
|
|
||||||
)
|
|
||||||
@@ -618,16 +618,28 @@ class TestACMERenew(IntegrationTest):
|
|
||||||
tasks.get_kdcinfo(host)
|
|
||||||
assert result.returncode == 0
|
|
||||||
|
|
||||||
- yield
|
|
||||||
+ yield _issue_and_expire_acme_cert
|
|
||||||
|
|
||||||
- # move back date
|
|
||||||
- for host in self.clients[0], self.master:
|
|
||||||
- tasks.kdestroy_all(host)
|
|
||||||
- tasks.move_date(host, 'start', '-90days')
|
|
||||||
- tasks.kinit_admin(host)
|
|
||||||
+ # move back date
|
|
||||||
+ for host in hosts:
|
|
||||||
+ tasks.move_date(host, 'start', '-90days')
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+class TestACMERenew(IntegrationTest):
|
|
||||||
+
|
|
||||||
+ num_clients = 1
|
|
||||||
+
|
|
||||||
+ @classmethod
|
|
||||||
+ def install(cls, mh):
|
|
||||||
+
|
|
||||||
+ # install packages before client install in case of IPA DNS problems
|
|
||||||
+ cls.acme_server = prepare_acme_client(cls.master, cls.clients[0])
|
|
||||||
+
|
|
||||||
+ tasks.install_master(cls.master, setup_dns=True)
|
|
||||||
+ tasks.install_client(cls.master, cls.clients[0])
|
|
||||||
|
|
||||||
@pytest.mark.skipif(skip_certbot_tests, reason='certbot not available')
|
|
||||||
- def test_renew(self, issue_and_expire_cert):
|
|
||||||
+ def test_renew(self, issue_and_expire_acme_cert):
|
|
||||||
"""Test if ACME renews the issued cert with cerbot
|
|
||||||
|
|
||||||
This test is to check if ACME certificate renews upon
|
|
||||||
@@ -635,6 +647,8 @@ class TestACMERenew(IntegrationTest):
|
|
||||||
|
|
||||||
related: https://pagure.io/freeipa/issue/4751
|
|
||||||
"""
|
|
||||||
+ issue_and_expire_acme_cert(
|
|
||||||
+ self.master, self.clients[0], self.acme_server)
|
|
||||||
data = self.clients[0].get_file_contents(
|
|
||||||
f'/etc/letsencrypt/live/{self.clients[0].hostname}/cert.pem'
|
|
||||||
)
|
|
||||||
@@ -656,6 +670,7 @@ class TestACMEPrune(IntegrationTest):
|
|
||||||
"""Validate that ipa-acme-manage configures dogtag for pruning"""
|
|
||||||
|
|
||||||
random_serial = True
|
|
||||||
+ num_clients = 1
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def install(cls, mh):
|
|
||||||
@@ -663,6 +678,8 @@ class TestACMEPrune(IntegrationTest):
|
|
||||||
raise pytest.skip("RNSv3 not supported")
|
|
||||||
tasks.install_master(cls.master, setup_dns=True,
|
|
||||||
random_serial=True)
|
|
||||||
+ cls.acme_server = prepare_acme_client(cls.master, cls.clients[0])
|
|
||||||
+ tasks.install_client(cls.master, cls.clients[0])
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def uninstall(cls, mh):
|
|
||||||
@@ -718,7 +735,7 @@ class TestACMEPrune(IntegrationTest):
|
|
||||||
['ipa-acme-manage', 'pruning',
|
|
||||||
'--requestretention=60',
|
|
||||||
'--requestretentionunit=minute',
|
|
||||||
- '--requestresearchsizelimit=2000',
|
|
||||||
+ '--requestsearchsizelimit=2000',
|
|
||||||
'--requestsearchtimelimit=5',]
|
|
||||||
)
|
|
||||||
cs_cfg = self.master.get_file_contents(paths.CA_CS_CFG_PATH)
|
|
||||||
@@ -741,7 +758,7 @@ class TestACMEPrune(IntegrationTest):
|
|
||||||
|
|
||||||
self.master.run_command(
|
|
||||||
['ipa-acme-manage', 'pruning',
|
|
||||||
- '--cron="0 23 1 * *',]
|
|
||||||
+ '--cron=0 23 1 * *',]
|
|
||||||
)
|
|
||||||
cs_cfg = self.master.get_file_contents(paths.CA_CS_CFG_PATH)
|
|
||||||
assert (
|
|
||||||
@@ -760,7 +777,7 @@ class TestACMEPrune(IntegrationTest):
|
|
||||||
'--enable', '--disable'],
|
|
||||||
raiseonerr=False
|
|
||||||
)
|
|
||||||
- assert result.returncode == 1
|
|
||||||
+ assert result.returncode == 2
|
|
||||||
assert "Cannot both enable and disable" in result.stderr_text
|
|
||||||
|
|
||||||
for cmd in ('--config-show', '--run'):
|
|
||||||
@@ -769,20 +786,20 @@ class TestACMEPrune(IntegrationTest):
|
|
||||||
cmd, '--enable'],
|
|
||||||
raiseonerr=False
|
|
||||||
)
|
|
||||||
- assert result.returncode == 1
|
|
||||||
+ assert result.returncode == 2
|
|
||||||
assert "Cannot change and show config" in result.stderr_text
|
|
||||||
|
|
||||||
result = self.master.run_command(
|
|
||||||
['ipa-acme-manage', 'pruning',
|
|
||||||
- '--cron="* *"'],
|
|
||||||
+ '--cron=* *'],
|
|
||||||
raiseonerr=False
|
|
||||||
)
|
|
||||||
- assert result.returncode == 1
|
|
||||||
- assert "Invalid format format --cron" in result.stderr_text
|
|
||||||
+ assert result.returncode == 2
|
|
||||||
+ assert "Invalid format for --cron" in result.stderr_text
|
|
||||||
|
|
||||||
result = self.master.run_command(
|
|
||||||
['ipa-acme-manage', 'pruning',
|
|
||||||
- '--cron="100 * * * *"'],
|
|
||||||
+ '--cron=100 * * * *'],
|
|
||||||
raiseonerr=False
|
|
||||||
)
|
|
||||||
assert result.returncode == 1
|
|
||||||
@@ -790,8 +807,205 @@ class TestACMEPrune(IntegrationTest):
|
|
||||||
|
|
||||||
result = self.master.run_command(
|
|
||||||
['ipa-acme-manage', 'pruning',
|
|
||||||
- '--cron="10 1-5 * * *"'],
|
|
||||||
+ '--cron=10 1-5 * * *'],
|
|
||||||
raiseonerr=False
|
|
||||||
)
|
|
||||||
assert result.returncode == 1
|
|
||||||
assert "1-5 ranges are not supported" in result.stderr_text
|
|
||||||
+
|
|
||||||
+ def test_prune_cert_manual(self, issue_and_expire_acme_cert):
|
|
||||||
+ """Test to prune expired certificate by manual run"""
|
|
||||||
+ if (tasks.get_pki_version(self.master)
|
|
||||||
+ < tasks.parse_version('11.3.0')):
|
|
||||||
+ raise pytest.skip("Certificate pruning is not available")
|
|
||||||
+
|
|
||||||
+ issue_and_expire_acme_cert(
|
|
||||||
+ self.master, self.clients[0], self.acme_server)
|
|
||||||
+
|
|
||||||
+ # check that the certificate issued for the client
|
|
||||||
+ result = self.master.run_command(
|
|
||||||
+ ['ipa', 'cert-find', '--subject', self.clients[0].hostname]
|
|
||||||
+ )
|
|
||||||
+ assert f'CN={self.clients[0].hostname}' in result.stdout_text
|
|
||||||
+
|
|
||||||
+ # run prune command manually
|
|
||||||
+ self.master.run_command(['ipa-acme-manage', 'pruning', '--enable'])
|
|
||||||
+ self.master.run_command(['ipactl', 'restart'])
|
|
||||||
+ self.master.run_command(['ipa-acme-manage', 'pruning', '--run'])
|
|
||||||
+ # wait for cert to get prune
|
|
||||||
+ time.sleep(50)
|
|
||||||
+
|
|
||||||
+ # check if client cert is removed
|
|
||||||
+ result = self.master.run_command(
|
|
||||||
+ ['ipa', 'cert-find', '--subject', self.clients[0].hostname],
|
|
||||||
+ raiseonerr=False
|
|
||||||
+ )
|
|
||||||
+ assert f'CN={self.clients[0].hostname}' not in result.stdout_text
|
|
||||||
+
|
|
||||||
+ def test_prune_cert_cron(self, issue_and_expire_acme_cert):
|
|
||||||
+ """Test to prune expired certificate by cron job"""
|
|
||||||
+ if (tasks.get_pki_version(self.master)
|
|
||||||
+ < tasks.parse_version('11.3.0')):
|
|
||||||
+ raise pytest.skip("Certificate pruning is not available")
|
|
||||||
+
|
|
||||||
+ issue_and_expire_acme_cert(
|
|
||||||
+ self.master, self.clients[0], self.acme_server)
|
|
||||||
+
|
|
||||||
+ # check that the certificate issued for the client
|
|
||||||
+ result = self.master.run_command(
|
|
||||||
+ ['ipa', 'cert-find', '--subject', self.clients[0].hostname]
|
|
||||||
+ )
|
|
||||||
+ assert f'CN={self.clients[0].hostname}' in result.stdout_text
|
|
||||||
+
|
|
||||||
+ # enable pruning
|
|
||||||
+ self.master.run_command(['ipa-acme-manage', 'pruning', '--enable'])
|
|
||||||
+
|
|
||||||
+ # cron would be set to run the next minute
|
|
||||||
+ cron_minute = self.master.run_command(
|
|
||||||
+ [
|
|
||||||
+ "python3",
|
|
||||||
+ "-c",
|
|
||||||
+ (
|
|
||||||
+ "from datetime import datetime; "
|
|
||||||
+ "print(int(datetime.now().strftime('%M')) + 5)"
|
|
||||||
+ ),
|
|
||||||
+ ]
|
|
||||||
+ ).stdout_text.strip()
|
|
||||||
+ self.master.run_command(
|
|
||||||
+ ['ipa-acme-manage', 'pruning',
|
|
||||||
+ f'--cron={cron_minute} * * * *']
|
|
||||||
+ )
|
|
||||||
+ self.master.run_command(['ipactl', 'restart'])
|
|
||||||
+ # wait for 5 minutes to cron to execute and 20 sec for just in case
|
|
||||||
+ time.sleep(320)
|
|
||||||
+
|
|
||||||
+ # check if client cert is removed
|
|
||||||
+ result = self.master.run_command(
|
|
||||||
+ ['ipa', 'cert-find', '--subject', self.clients[0].hostname],
|
|
||||||
+ raiseonerr=False
|
|
||||||
+ )
|
|
||||||
+ assert f'CN={self.clients[0].hostname}' not in result.stdout_text
|
|
||||||
+
|
|
||||||
+ def test_prune_cert_retention_unit(self, issue_and_expire_acme_cert):
|
|
||||||
+ """Test to prune expired certificate with retention unit option"""
|
|
||||||
+ if (tasks.get_pki_version(self.master)
|
|
||||||
+ < tasks.parse_version('11.3.0')):
|
|
||||||
+ raise pytest.skip("Certificate pruning is not available")
|
|
||||||
+ issue_and_expire_acme_cert(
|
|
||||||
+ self.master, self.clients[0], self.acme_server)
|
|
||||||
+
|
|
||||||
+ # check that the certificate issued for the client
|
|
||||||
+ result = self.master.run_command(
|
|
||||||
+ ['ipa', 'cert-find', '--subject', self.clients[0].hostname]
|
|
||||||
+ )
|
|
||||||
+ assert f'CN={self.clients[0].hostname}' in result.stdout_text
|
|
||||||
+
|
|
||||||
+ # enable pruning
|
|
||||||
+ self.master.run_command(['ipa-acme-manage', 'pruning', '--enable'])
|
|
||||||
+
|
|
||||||
+ # certretention set to 5 min
|
|
||||||
+ self.master.run_command(
|
|
||||||
+ ['ipa-acme-manage', 'pruning',
|
|
||||||
+ '--certretention=5', '--certretentionunit=minute']
|
|
||||||
+ )
|
|
||||||
+ self.master.run_command(['ipactl', 'restart'])
|
|
||||||
+
|
|
||||||
+ # wait for 5 min and check if expired cert is removed
|
|
||||||
+ time.sleep(310)
|
|
||||||
+ self.master.run_command(['ipa-acme-manage', 'pruning', '--run'])
|
|
||||||
+ result = self.master.run_command(
|
|
||||||
+ ['ipa', 'cert-find', '--subject', self.clients[0].hostname],
|
|
||||||
+ raiseonerr=False
|
|
||||||
+ )
|
|
||||||
+ assert f'CN={self.clients[0].hostname}' not in result.stdout_text
|
|
||||||
+
|
|
||||||
+ def test_prune_cert_search_size_limit(self, issue_and_expire_acme_cert):
|
|
||||||
+ """Test to prune expired certificate with search size limit option"""
|
|
||||||
+ if (tasks.get_pki_version(self.master)
|
|
||||||
+ < tasks.parse_version('11.3.0')):
|
|
||||||
+ raise pytest.skip("Certificate pruning is not available")
|
|
||||||
+ no_of_cert = 10
|
|
||||||
+ search_size_limit = 5
|
|
||||||
+ issue_and_expire_acme_cert(
|
|
||||||
+ self.master, self.clients[0], self.acme_server, no_of_cert)
|
|
||||||
+
|
|
||||||
+ # check that the certificate issued for the client
|
|
||||||
+ result = self.master.run_command(
|
|
||||||
+ ['ipa', 'cert-find', '--subject', self.clients[0].hostname]
|
|
||||||
+ )
|
|
||||||
+ assert f'CN={self.clients[0].hostname}' in result.stdout_text
|
|
||||||
+ assert f'Number of entries returned {no_of_cert}'
|
|
||||||
+
|
|
||||||
+ # enable pruning
|
|
||||||
+ self.master.run_command(['ipa-acme-manage', 'pruning', '--enable'])
|
|
||||||
+
|
|
||||||
+ # certretention set to 5 min
|
|
||||||
+ self.master.run_command(
|
|
||||||
+ ['ipa-acme-manage', 'pruning',
|
|
||||||
+ f'--certsearchsizelimit={search_size_limit}',
|
|
||||||
+ '--certsearchtimelimit=100']
|
|
||||||
+ )
|
|
||||||
+ self.master.run_command(['ipactl', 'restart'])
|
|
||||||
+
|
|
||||||
+ # prune the certificates
|
|
||||||
+ self.master.run_command(['ipa-acme-manage', 'pruning', '--run'])
|
|
||||||
+
|
|
||||||
+ # check if 5 expired cert is removed
|
|
||||||
+ result = self.master.run_command(
|
|
||||||
+ ['ipa', 'cert-find', '--subject', self.clients[0].hostname]
|
|
||||||
+ )
|
|
||||||
+ assert f'Number of entries returned {no_of_cert - search_size_limit}'
|
|
||||||
+
|
|
||||||
+ def test_prune_config_show(self, issue_and_expire_acme_cert):
|
|
||||||
+ """Test to check config-show command shows set param"""
|
|
||||||
+ if (tasks.get_pki_version(self.master)
|
|
||||||
+ < tasks.parse_version('11.3.0')):
|
|
||||||
+ raise pytest.skip("Certificate pruning is not available")
|
|
||||||
+
|
|
||||||
+ self.master.run_command(['ipa-acme-manage', 'pruning', '--enable'])
|
|
||||||
+ self.master.run_command(
|
|
||||||
+ ['ipa-acme-manage', 'pruning',
|
|
||||||
+ '--cron=0 0 1 * *']
|
|
||||||
+ )
|
|
||||||
+ self.master.run_command(
|
|
||||||
+ ['ipa-acme-manage', 'pruning',
|
|
||||||
+ '--certretention=30', '--certretentionunit=day']
|
|
||||||
+ )
|
|
||||||
+ self.master.run_command(
|
|
||||||
+ ['ipa-acme-manage', 'pruning',
|
|
||||||
+ '--certsearchsizelimit=1000', '--certsearchtimelimit=0']
|
|
||||||
+ )
|
|
||||||
+ self.master.run_command(
|
|
||||||
+ ['ipa-acme-manage', 'pruning',
|
|
||||||
+ '--requestretention=30', '--requestretentionunit=day']
|
|
||||||
+ )
|
|
||||||
+ self.master.run_command(
|
|
||||||
+ ['ipa-acme-manage', 'pruning',
|
|
||||||
+ '--requestsearchsizelimit=1000', '--requestsearchtimelimit=0']
|
|
||||||
+ )
|
|
||||||
+ result = self.master.run_command(
|
|
||||||
+ ['ipa-acme-manage', 'pruning', '--config-show']
|
|
||||||
+ )
|
|
||||||
+ assert 'Status: enabled' in result.stdout_text
|
|
||||||
+ assert 'Certificate Retention Time: 30' in result.stdout_text
|
|
||||||
+ assert 'Certificate Retention Unit: day' in result.stdout_text
|
|
||||||
+ assert 'Certificate Search Size Limit: 1000' in result.stdout_text
|
|
||||||
+ assert 'Certificate Search Time Limit: 100' in result.stdout_text
|
|
||||||
+ assert 'Request Retention Time: 30' in result.stdout_text
|
|
||||||
+ assert 'Request Retention Unit: day' in result.stdout_text
|
|
||||||
+ assert 'Request Search Size Limit' in result.stdout_text
|
|
||||||
+ assert 'Request Search Time Limit: 100' in result.stdout_text
|
|
||||||
+ assert 'cron Schedule: 0 0 1 * *' in result.stdout_text
|
|
||||||
+
|
|
||||||
+ def test_prune_disable(self, issue_and_expire_acme_cert):
|
|
||||||
+ """Test prune command throw error after disabling the pruning"""
|
|
||||||
+ if (tasks.get_pki_version(self.master)
|
|
||||||
+ < tasks.parse_version('11.3.0')):
|
|
||||||
+ raise pytest.skip("Certificate pruning is not available")
|
|
||||||
+
|
|
||||||
+ self.master.run_command(['ipa-acme-manage', 'pruning', '--disable'])
|
|
||||||
+ result = self.master.run_command(
|
|
||||||
+ ['ipa-acme-manage', 'pruning',
|
|
||||||
+ '--cron=0 0 1 * *']
|
|
||||||
+ )
|
|
||||||
+ assert 'Status: disabled' in result.stdout_text
|
|
||||||
--
|
|
||||||
2.39.1
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
|||||||
|
From 13d5e88eb4ebb7a0132cbb050a9d230304ecbcff Mon Sep 17 00:00:00 2001
|
||||||
|
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
Date: Wed, 2 Aug 2023 15:41:57 +0200
|
||||||
|
Subject: [PATCH] ipatests: update expected webui msg for admin deletion
|
||||||
|
|
||||||
|
The deletion of the admin is now forbidden (even if it is
|
||||||
|
not the last member of the admins group) and the error
|
||||||
|
message has changed from "admin cannot be deleted or
|
||||||
|
disabled because it is the last member of group admins"
|
||||||
|
to " user admin cannot be deleted/modified: privileged user".
|
||||||
|
|
||||||
|
Update the expected message in the webui test.
|
||||||
|
|
||||||
|
Related: https://pagure.io/freeipa/issue/8878
|
||||||
|
|
||||||
|
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||||
|
---
|
||||||
|
ipatests/test_webui/test_user.py | 3 +--
|
||||||
|
1 file changed, 1 insertion(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/ipatests/test_webui/test_user.py b/ipatests/test_webui/test_user.py
|
||||||
|
index 8d44fbdb9380c94058307b02a96299d0e178cdc7..a8a92d00c7e1f40ef10eb9133cea8752daafe730 100644
|
||||||
|
--- a/ipatests/test_webui/test_user.py
|
||||||
|
+++ b/ipatests/test_webui/test_user.py
|
||||||
|
@@ -50,8 +50,7 @@ INV_FIRSTNAME = ("invalid 'first': Leading and trailing spaces are "
|
||||||
|
FIELD_REQ = 'Required field'
|
||||||
|
ERR_INCLUDE = 'may only include letters, numbers, _, -, . and $'
|
||||||
|
ERR_MISMATCH = 'Passwords must match'
|
||||||
|
-ERR_ADMIN_DEL = ('admin cannot be deleted or disabled because it is the last '
|
||||||
|
- 'member of group admins')
|
||||||
|
+ERR_ADMIN_DEL = ('user admin cannot be deleted/modified: privileged user')
|
||||||
|
USR_EXIST = 'user with name "{}" already exists'
|
||||||
|
ENTRY_EXIST = 'This entry already exists'
|
||||||
|
ACTIVE_ERR = 'active user with name "{}" already exists'
|
||||||
|
--
|
||||||
|
2.41.0
|
||||||
|
|
@ -1,65 +0,0 @@
|
|||||||
From 88b9be29036a3580a8bccd31986fc30faa9852df Mon Sep 17 00:00:00 2001
|
|
||||||
From: mbhalodi <mbhalodi@redhat.com>
|
|
||||||
Date: Tue, 14 Feb 2023 15:04:58 +0530
|
|
||||||
Subject: [PATCH] ipatests: ensure that ipa automember-rebuild prints a warning
|
|
||||||
|
|
||||||
ipa automember-rebuild now prints a warning about CPU usage.
|
|
||||||
Ensure that the warning is properly displayed.
|
|
||||||
|
|
||||||
Related: https://pagure.io/freeipa/issue/9320
|
|
||||||
|
|
||||||
Signed-off-by: mbhalodi <mbhalodi@redhat.com>
|
|
||||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
---
|
|
||||||
ipatests/test_integration/test_automember.py | 13 ++++++++++---
|
|
||||||
1 file changed, 10 insertions(+), 3 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/ipatests/test_integration/test_automember.py b/ipatests/test_integration/test_automember.py
|
|
||||||
index f013964140714db046a1aa6a92409244b2137727..7acd0d7bf895fec970f2bda8b54f4496280525b6 100644
|
|
||||||
--- a/ipatests/test_integration/test_automember.py
|
|
||||||
+++ b/ipatests/test_integration/test_automember.py
|
|
||||||
@@ -10,6 +10,9 @@ from ipapython.dn import DN
|
|
||||||
from ipatests.pytest_ipa.integration import tasks
|
|
||||||
from ipatests.test_integration.base import IntegrationTest
|
|
||||||
|
|
||||||
+msg = ('IMPORTANT: In case of a high number of users, hosts or '
|
|
||||||
+ 'groups, the operation may require high CPU usage.')
|
|
||||||
+
|
|
||||||
|
|
||||||
class TestAutounmembership(IntegrationTest):
|
|
||||||
"""Tests for autounmembership feature.
|
|
||||||
@@ -206,11 +209,13 @@ class TestAutounmembership(IntegrationTest):
|
|
||||||
assert self.is_user_member_of_group(user2, group1)
|
|
||||||
|
|
||||||
# Running automember-build so that user is part of correct group
|
|
||||||
- self.master.run_command(['ipa', 'automember-rebuild',
|
|
||||||
- '--users=%s' % user2])
|
|
||||||
+ result = self.master.run_command(['ipa', 'automember-rebuild',
|
|
||||||
+ '--users=%s' % user2])
|
|
||||||
assert self.is_user_member_of_group(user2, group2)
|
|
||||||
assert not self.is_user_member_of_group(user2, group1)
|
|
||||||
|
|
||||||
+ assert msg in result.stdout_text
|
|
||||||
+
|
|
||||||
finally:
|
|
||||||
# testcase cleanup
|
|
||||||
self.remove_user_automember(user2, raiseonerr=False)
|
|
||||||
@@ -240,12 +245,14 @@ class TestAutounmembership(IntegrationTest):
|
|
||||||
assert self.is_host_member_of_hostgroup(host2, hostgroup1)
|
|
||||||
|
|
||||||
# Running the automember-build so host is part of correct hostgroup
|
|
||||||
- self.master.run_command(
|
|
||||||
+ result = self.master.run_command(
|
|
||||||
['ipa', 'automember-rebuild', '--hosts=%s' % host2]
|
|
||||||
)
|
|
||||||
assert self.is_host_member_of_hostgroup(host2, hostgroup2)
|
|
||||||
assert not self.is_host_member_of_hostgroup(host2, hostgroup1)
|
|
||||||
|
|
||||||
+ assert msg in result.stdout_text
|
|
||||||
+
|
|
||||||
finally:
|
|
||||||
# testcase cleanup
|
|
||||||
self.remove_host_automember(host2, raiseonerr=False)
|
|
||||||
--
|
|
||||||
2.39.1
|
|
||||||
|
|
@ -0,0 +1,70 @@
|
|||||||
|
From ff6cfcacd67a0461a0341e17854732cbe301f1d6 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Mohammad Rizwan <myusuf@redhat.com>
|
||||||
|
Date: Wed, 2 Aug 2023 12:48:40 +0530
|
||||||
|
Subject: [PATCH] ipatests: remove fixture call and wait to get things settle
|
||||||
|
|
||||||
|
system date moved in order to expire the certs. Sometime it
|
||||||
|
is observed that subsequent operation fails with 500 error for CA,
|
||||||
|
hence restart the services after moving date and wait for sometime
|
||||||
|
to get things settle.
|
||||||
|
|
||||||
|
Also the tests was calling fixture which is not required for it, hence
|
||||||
|
removed it as well.
|
||||||
|
|
||||||
|
Fixes: https://pagure.io/freeipa/issue/9348
|
||||||
|
|
||||||
|
Signed-off-by: Mohammad Rizwan <myusuf@redhat.com>
|
||||||
|
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
---
|
||||||
|
ipatests/test_integration/test_acme.py | 14 ++++++++++++--
|
||||||
|
1 file changed, 12 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/ipatests/test_integration/test_acme.py b/ipatests/test_integration/test_acme.py
|
||||||
|
index cca20983e65f99d5ba0bb7bc6dc2b5684a6f37d9..c7389732cd067d49541cd04ea6687a6b95b4669f 100644
|
||||||
|
--- a/ipatests/test_integration/test_acme.py
|
||||||
|
+++ b/ipatests/test_integration/test_acme.py
|
||||||
|
@@ -606,6 +606,11 @@ def issue_and_expire_acme_cert():
|
||||||
|
tasks.kdestroy_all(host)
|
||||||
|
tasks.move_date(host, 'stop', '+90days+60minutes')
|
||||||
|
|
||||||
|
+ # restart ipa services as date moved and wait to get things settle
|
||||||
|
+ time.sleep(10)
|
||||||
|
+ master.run_command(['ipactl', 'restart'])
|
||||||
|
+ time.sleep(10)
|
||||||
|
+
|
||||||
|
tasks.get_kdcinfo(master)
|
||||||
|
# Note raiseonerr=False:
|
||||||
|
# the assert is located after kdcinfo retrieval.
|
||||||
|
@@ -627,6 +632,11 @@ def issue_and_expire_acme_cert():
|
||||||
|
for host in hosts:
|
||||||
|
tasks.move_date(host, 'start', '-90days-60minutes')
|
||||||
|
|
||||||
|
+ # restart ipa services as date moved and wait to get things settle
|
||||||
|
+ time.sleep(10)
|
||||||
|
+ hosts[0].run_command(['ipactl', 'restart'])
|
||||||
|
+ time.sleep(10)
|
||||||
|
+
|
||||||
|
|
||||||
|
class TestACMERenew(IntegrationTest):
|
||||||
|
|
||||||
|
@@ -960,7 +970,7 @@ class TestACMEPrune(IntegrationTest):
|
||||||
|
)
|
||||||
|
assert f'Number of entries returned {no_of_cert - search_size_limit}'
|
||||||
|
|
||||||
|
- def test_prune_config_show(self, issue_and_expire_acme_cert):
|
||||||
|
+ def test_prune_config_show(self):
|
||||||
|
"""Test to check config-show command shows set param"""
|
||||||
|
if (tasks.get_pki_version(self.master)
|
||||||
|
< tasks.parse_version('11.3.0')):
|
||||||
|
@@ -1001,7 +1011,7 @@ class TestACMEPrune(IntegrationTest):
|
||||||
|
assert 'Request Search Time Limit: 0' in result.stdout_text
|
||||||
|
assert 'cron Schedule: 0 0 1 * *' in result.stdout_text
|
||||||
|
|
||||||
|
- def test_prune_disable(self, issue_and_expire_acme_cert):
|
||||||
|
+ def test_prune_disable(self):
|
||||||
|
"""Test prune command throw error after disabling the pruning"""
|
||||||
|
if (tasks.get_pki_version(self.master)
|
||||||
|
< tasks.parse_version('11.3.0')):
|
||||||
|
--
|
||||||
|
2.41.0
|
||||||
|
|
60
SOURCES/0022-ipatests-fix-test_topology.patch
Normal file
60
SOURCES/0022-ipatests-fix-test_topology.patch
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
From 1278e614dd93bf0ac3d6e0c36cb9c277808afb2c Mon Sep 17 00:00:00 2001
|
||||||
|
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
Date: Fri, 11 Aug 2023 08:01:18 +0200
|
||||||
|
Subject: [PATCH] ipatests: fix test_topology
|
||||||
|
|
||||||
|
The test TestTopologyOptions::test_add_remove_segment is
|
||||||
|
randomly failing downstream. Test scenario:
|
||||||
|
- create a line topology master <-> repl1 <-> repl2
|
||||||
|
- create user on master
|
||||||
|
- wait for repl success on master
|
||||||
|
- check that the user is seen on repl2
|
||||||
|
|
||||||
|
The test waits for replication to complete on the master but
|
||||||
|
it should also wait for the replication to complete on repl1
|
||||||
|
before checking the user presence on repl2.
|
||||||
|
|
||||||
|
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
Reviewed-By: Anuja More <amore@redhat.com>
|
||||||
|
---
|
||||||
|
ipatests/test_integration/test_topology.py | 7 +++++++
|
||||||
|
1 file changed, 7 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/ipatests/test_integration/test_topology.py b/ipatests/test_integration/test_topology.py
|
||||||
|
index 8a240fa3c081a05b8f4501fe48694e01086003a1..618c9d5dcce994cd0359a291b044eb2cf0bddc74 100644
|
||||||
|
--- a/ipatests/test_integration/test_topology.py
|
||||||
|
+++ b/ipatests/test_integration/test_topology.py
|
||||||
|
@@ -124,6 +124,9 @@ class TestTopologyOptions(IntegrationTest):
|
||||||
|
self.replicas[0],
|
||||||
|
self.replicas[1])
|
||||||
|
assert err == "", err
|
||||||
|
+ # At this point we have replicas[1] <-> master <-> replicas[0]
|
||||||
|
+ # ^--------------------------^
|
||||||
|
+
|
||||||
|
# Make sure the new segment is shown by `ipa topologysegment-find`
|
||||||
|
result1 = self.master.run_command(['ipa', 'topologysegment-find',
|
||||||
|
DOMAIN_SUFFIX_NAME]).stdout_text
|
||||||
|
@@ -137,9 +140,12 @@ class TestTopologyOptions(IntegrationTest):
|
||||||
|
deleteme = find_segment(self.master, self.replicas[1])
|
||||||
|
returncode, error = tasks.destroy_segment(self.master, deleteme)
|
||||||
|
assert returncode == 0, error
|
||||||
|
+ # At this point we have master <-> replicas[0] <-> replicas[1]
|
||||||
|
+
|
||||||
|
# Wait till replication ends and make sure replica1 does not have
|
||||||
|
# segment that was deleted on master
|
||||||
|
master_ldap = self.master.ldap_connect()
|
||||||
|
+ repl_ldap = self.replicas[0].ldap_connect()
|
||||||
|
tasks.wait_for_replication(master_ldap)
|
||||||
|
result3 = self.replicas[0].run_command(['ipa', 'topologysegment-find',
|
||||||
|
DOMAIN_SUFFIX_NAME]).stdout_text
|
||||||
|
@@ -150,6 +156,7 @@ class TestTopologyOptions(IntegrationTest):
|
||||||
|
'--first', 'test',
|
||||||
|
'--last', 'user'])
|
||||||
|
tasks.wait_for_replication(master_ldap)
|
||||||
|
+ tasks.wait_for_replication(repl_ldap)
|
||||||
|
result4 = self.replicas[1].run_command(['ipa', 'user-find'])
|
||||||
|
assert('someuser' in result4.stdout_text), 'User not found: someuser'
|
||||||
|
# We end up having a line topology: master <-> replica1 <-> replica2
|
||||||
|
--
|
||||||
|
2.41.0
|
||||||
|
|
@ -1,74 +0,0 @@
|
|||||||
From e76b219c21d53b6bccce4ea3d18e2b61ac835e1f Mon Sep 17 00:00:00 2001
|
|
||||||
From: Mohammad Rizwan <myusuf@redhat.com>
|
|
||||||
Date: Mon, 20 Feb 2023 15:33:09 +0530
|
|
||||||
Subject: [PATCH] ipatests: fix tests in TestACMEPrune
|
|
||||||
|
|
||||||
When cron_minute + 5 > 59, cron job throwing error for it.
|
|
||||||
i.e 58 + 5 = 63 which is not acceptable value for cron minute.
|
|
||||||
|
|
||||||
Second fix is related to mismatch of confing setting and corresponding
|
|
||||||
assert.
|
|
||||||
|
|
||||||
Third fix is related to extending time by 60 minutes to properly
|
|
||||||
expire the certs.
|
|
||||||
|
|
||||||
related: https://pagure.io/freeipa/issue/9294
|
|
||||||
|
|
||||||
Signed-off-by: Mohammad Rizwan <myusuf@redhat.com>
|
|
||||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
|
||||||
---
|
|
||||||
ipatests/test_integration/test_acme.py | 15 ++++++++-------
|
|
||||||
1 file changed, 8 insertions(+), 7 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/ipatests/test_integration/test_acme.py b/ipatests/test_integration/test_acme.py
|
|
||||||
index 1334be52f4530dd8b2a4207744146cd0eb5477a3..49b173060f88d4b8e876d8e3461a935938518b44 100644
|
|
||||||
--- a/ipatests/test_integration/test_acme.py
|
|
||||||
+++ b/ipatests/test_integration/test_acme.py
|
|
||||||
@@ -600,7 +600,7 @@ def issue_and_expire_acme_cert():
|
|
||||||
# move system date to expire acme cert
|
|
||||||
for host in hosts:
|
|
||||||
tasks.kdestroy_all(host)
|
|
||||||
- tasks.move_date(host, 'stop', '+90days')
|
|
||||||
+ tasks.move_date(host, 'stop', '+90days+60minutes')
|
|
||||||
|
|
||||||
time.sleep(10)
|
|
||||||
tasks.get_kdcinfo(host)
|
|
||||||
@@ -622,7 +622,7 @@ def issue_and_expire_acme_cert():
|
|
||||||
|
|
||||||
# move back date
|
|
||||||
for host in hosts:
|
|
||||||
- tasks.move_date(host, 'start', '-90days')
|
|
||||||
+ tasks.move_date(host, 'start', '-90days-60minutes')
|
|
||||||
|
|
||||||
|
|
||||||
class TestACMERenew(IntegrationTest):
|
|
||||||
@@ -866,8 +866,9 @@ class TestACMEPrune(IntegrationTest):
|
|
||||||
"python3",
|
|
||||||
"-c",
|
|
||||||
(
|
|
||||||
- "from datetime import datetime; "
|
|
||||||
- "print(int(datetime.now().strftime('%M')) + 5)"
|
|
||||||
+ "from datetime import datetime, timedelta; "
|
|
||||||
+ "print(int((datetime.now() + "
|
|
||||||
+ "timedelta(minutes=5)).strftime('%M')))"
|
|
||||||
),
|
|
||||||
]
|
|
||||||
).stdout_text.strip()
|
|
||||||
@@ -990,11 +991,11 @@ class TestACMEPrune(IntegrationTest):
|
|
||||||
assert 'Certificate Retention Time: 30' in result.stdout_text
|
|
||||||
assert 'Certificate Retention Unit: day' in result.stdout_text
|
|
||||||
assert 'Certificate Search Size Limit: 1000' in result.stdout_text
|
|
||||||
- assert 'Certificate Search Time Limit: 100' in result.stdout_text
|
|
||||||
+ assert 'Certificate Search Time Limit: 0' in result.stdout_text
|
|
||||||
assert 'Request Retention Time: 30' in result.stdout_text
|
|
||||||
assert 'Request Retention Unit: day' in result.stdout_text
|
|
||||||
- assert 'Request Search Size Limit' in result.stdout_text
|
|
||||||
- assert 'Request Search Time Limit: 100' in result.stdout_text
|
|
||||||
+ assert 'Request Search Size Limit: 1000' in result.stdout_text
|
|
||||||
+ assert 'Request Search Time Limit: 0' in result.stdout_text
|
|
||||||
assert 'cron Schedule: 0 0 1 * *' in result.stdout_text
|
|
||||||
|
|
||||||
def test_prune_disable(self, issue_and_expire_acme_cert):
|
|
||||||
--
|
|
||||||
2.39.1
|
|
||||||
|
|
560
SOURCES/0023-ipatests-idm-api-related-tests.patch
Normal file
560
SOURCES/0023-ipatests-idm-api-related-tests.patch
Normal file
@ -0,0 +1,560 @@
|
|||||||
|
From ac6a2172f5dcb46701148c7b096ffa1b44076816 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sudhir Menon <sumenon@redhat.com>
|
||||||
|
Date: Thu, 27 Jul 2023 14:33:08 +0530
|
||||||
|
Subject: [PATCH] ipatests: idm api related tests.
|
||||||
|
|
||||||
|
IDM API related tests are automated in the
|
||||||
|
above PR
|
||||||
|
Ref: https://freeipa.readthedocs.io/en/latest/api/basic_usage.html
|
||||||
|
|
||||||
|
Signed-off-by: Sudhir Menon <sumenon@redhat.com>
|
||||||
|
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||||
|
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
---
|
||||||
|
ipatests/test_integration/test_idm_api.py | 534 ++++++++++++++++++++++
|
||||||
|
1 file changed, 534 insertions(+)
|
||||||
|
create mode 100644 ipatests/test_integration/test_idm_api.py
|
||||||
|
|
||||||
|
diff --git a/ipatests/test_integration/test_idm_api.py b/ipatests/test_integration/test_idm_api.py
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000000000000000000000000000000000000..eafef5dd8526bc14725d6bc32819cb5c7387f868
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/ipatests/test_integration/test_idm_api.py
|
||||||
|
@@ -0,0 +1,534 @@
|
||||||
|
+#
|
||||||
|
+# Copyright (C) 2018 FreeIPA Contributors see COPYING for license
|
||||||
|
+#
|
||||||
|
+from __future__ import absolute_import
|
||||||
|
+
|
||||||
|
+from ipatests.test_integration.base import IntegrationTest
|
||||||
|
+import textwrap
|
||||||
|
+
|
||||||
|
+API_INIT = """
|
||||||
|
+ from ipalib import api, errors
|
||||||
|
+ api.bootstrap_with_global_options(context="server")
|
||||||
|
+ api.finalize()
|
||||||
|
+ api.Backend.ldap2.connect()
|
||||||
|
+ """
|
||||||
|
+
|
||||||
|
+CERT = (
|
||||||
|
+ b"MIIEkDCCAvigAwIBAgIBCzANBgkqhkiG9w0BAQsFADA5MRcwFQYDVQQKD\n"
|
||||||
|
+ b"A5URVNUUkVBTE0uVEVTVDEeMBwGA1UEAwwVQ2VydGlmaWNhdGUgQXV0aG\n"
|
||||||
|
+ b"9yaXR5MB4XDTIzMDcyODE3MTIxOVoXDTI1MDcyODE3MTIxOVowKjEXMBU\n"
|
||||||
|
+ b"GA1UECgwOVEVTVFJFQUxNLlRFU1QxDzANBgNVBAMMBmpzbWl0aDCCASIw\n"
|
||||||
|
+ b"DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOF0XFrdVXmKp95AVZW5o\n"
|
||||||
|
+ b"BWcij6vJPqeU3UpzTLbM+fROhNaKMX9S+yXrJHifOmhCOuNA8TtptKVJx\n"
|
||||||
|
+ b"CIDZ1/5KwPBk4vrnwOBtVMCftHj87MabBqV/nmQQrCiKTcJu4aQEDI9Qh\n"
|
||||||
|
+ b"yza09EJKvG8KkpnyuShtkP2LgkUxIqkjBg4DLV7grO+I+aG17QTuQxUTy\n"
|
||||||
|
+ b"icfYDBnzD4hTKPLf7d9KNyG+sEeyN0gceLFMUYaQ4lyapcSzYJwOSAc2B\n"
|
||||||
|
+ b"EU73tLaJlQORHL7HmhxrjD1IgZyxFjp/ofLVZFFoJAqjz2FWzOxmQw+bc\n"
|
||||||
|
+ b"0WTzQjeSTGx+l3htj7MmhIRBMqr3Um6zXkLKMCAwEAAaOCATAwggEsMB8\n"
|
||||||
|
+ b"GA1UdIwQYMBaAFCIXu6QtsiBVo1yZQZ7MMHTl5Wj6MEAGCCsGAQUFBwEB\n"
|
||||||
|
+ b"BDQwMjAwBggrBgEFBQcwAYYkaHR0cDovL2lwYS1jYS50ZXN0cmVhbG0ud\n"
|
||||||
|
+ b"GVzdC9jYS9vY3NwMA4GA1UdDwEB/wQEAwIE8DAdBgNVHSUEFjAUBggrBg\n"
|
||||||
|
+ b"EFBQcDAQYIKwYBBQUHAwIweQYDVR0fBHIwcDBuoDagNIYyaHR0cDovL2l\n"
|
||||||
|
+ b"wYS1jYS50ZXN0cmVhbG0udGVzdC9pcGEvY3JsL01hc3RlckNSTC5iaW6i\n"
|
||||||
|
+ b"NKQyMDAxDjAMBgNVBAoMBWlwYWNhMR4wHAYDVQQDDBVDZXJ0aWZpY2F0Z\n"
|
||||||
|
+ b"SBBdXRob3JpdHkwHQYDVR0OBBYEFNwQNQAG8MsKQPwMFyGzRiMzRAa5MA\n"
|
||||||
|
+ b"0GCSqGSIb3DQEBCwUAA4IBgQB2g0mS8XAPI+aRBa5q7Vbp1245CvMP0Eq\n"
|
||||||
|
+ b"Cz6gvCNwtxW0UDKnB++d/YQ13ft+x9Xj3rB/M2YXxdxTpQnQQv34CUcyh\n"
|
||||||
|
+ b"PQKJthAsbKBpdusCGrbS54zKFR0MjxwOwIIDHuI6eu2AoSpsmYs5UGzQm\n"
|
||||||
|
+ b"oCfQhbImK7iGLy0rOHaON1cWAFmC6lzJ2TFELc4N3eLYGVZy2ZtyZTgA3\n"
|
||||||
|
+ b"l97rBCwbDDFF1JWoOByIq8Ij99ksyMXws++sNUpo/1l8Jt0Gn6RBiidZB\n"
|
||||||
|
+ b"ef4+kJN+t6RAAwRQ / 3cmEggXcFoV13KZ70PeMXeX6CKMwXIwt3q7A78\n"
|
||||||
|
+ b"Wc/0OIBREZLhXpkmogCzWCuatdzeBIhMhx0vDEzaxlhf32ZWfN5pFMpgq\n"
|
||||||
|
+ b"wLZsdwMf6J65kGbE5Pg3Yxk7OiByxZJnR8UlvbU3r6RhMWutD6C0aqqNt\n"
|
||||||
|
+ b"o3us5gTmfRc8Mf1l/BUgDqkBKOTU8FHREGemG1HoklBym/Pbua0VMUA+s\n"
|
||||||
|
+ b"0nECR4LLM/o9PCJ2Y3QPBZy8Hg=\n"
|
||||||
|
+)
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+class TestAPIScenario(IntegrationTest):
|
||||||
|
+ """
|
||||||
|
+ Tests for IDM API scenarios
|
||||||
|
+ """
|
||||||
|
+
|
||||||
|
+ topology = "line"
|
||||||
|
+
|
||||||
|
+ def create_and_run_script(self, filename, user_code_script):
|
||||||
|
+ self.master.put_file_contents(filename, user_code_script)
|
||||||
|
+ self.master.run_command(["python3", filename])
|
||||||
|
+ self.master.run_command(["rm", filename])
|
||||||
|
+
|
||||||
|
+ def test_idm_user_add(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that ipa user using api.Command["user_add"]
|
||||||
|
+ and then checks that user is displayed using
|
||||||
|
+ api.Command["user_show"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ api.Command["user_add"]("jsmith", givenname="John", sn="Smith",
|
||||||
|
+ ipauserauthtype="otp")
|
||||||
|
+ cmd = api.Command["user_show"]("jsmith", all=True)["result"]
|
||||||
|
+ assert 'otp' in cmd['ipauserauthtype']
|
||||||
|
+ assert 'John Smith' in cmd['cn']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/user_add.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_idm_user_find(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that user is displayed
|
||||||
|
+ using api.Command["user_find"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ cmd = api.Command["user_find"]("jsmith")
|
||||||
|
+ assert '1 user matched' in cmd['summary']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/user_find.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_idm_user_mod(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that user attribute is modified
|
||||||
|
+ using api.Command["user_mod"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ cmd = api.Command["user_mod"]("jsmith",
|
||||||
|
+ mail="jsmith@example.org")["result"]
|
||||||
|
+ assert 'jsmith@example.org' in cmd['mail']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/user_mod.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_disable_user(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that user is disabled
|
||||||
|
+ using api.Command["user_disable"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ cmd = api.Command["user_disable"]("jsmith")
|
||||||
|
+ assert 'Disabled user account "jsmith"' in cmd['summary']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/disable_user.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_enable_user(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that user is enabled
|
||||||
|
+ using api.Command["user_enable"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ cmd = api.Command["user_enable"]("jsmith")
|
||||||
|
+ assert 'Enabled user account "jsmith"' in cmd['summary']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/enable_user.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_create_ipa_group(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that group is created
|
||||||
|
+ using api.Command["group_add"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ cmd = api.Command["group_add"]("developers", gidnumber=500,
|
||||||
|
+ description="Developers")
|
||||||
|
+ assert 'Added group "developers"' in cmd['summary']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/create_group.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_show_ipa_group(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that group is displayed
|
||||||
|
+ using api.Command["group_show"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ cmd = api.Command["group_show"]("developers")
|
||||||
|
+ assert 'developers' in cmd['result']['cn']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/group_show.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_ipa_group_mod(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that group description is modified
|
||||||
|
+ using api.Command["group_mod"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ cmd = api.Command["group_mod"]("developers", description='developer')
|
||||||
|
+ ["result"]
|
||||||
|
+ assert 'Modified group "developers"' in cmd['summary']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/group_mod.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_add_members_to_ipa_group(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that member is added to group
|
||||||
|
+ using api.Command["group_add_member"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ cmd = api.Command["group_add_member"]("developers",
|
||||||
|
+ user='jsmith')["result"]
|
||||||
|
+ assert 'jsmith' in cmd['member_user']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/create_group_members.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_ipa_group_find(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that group is displayed
|
||||||
|
+ using api.Command["group_find"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ cmd = api.Command["group_find"]("developers")
|
||||||
|
+ assert '1 group matched' in cmd['summary']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/group_find.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_remove_member_group(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that group member is removed
|
||||||
|
+ using api.Command["group_remove_member"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ cmd = api.Command["group_remove_member"]("developers",
|
||||||
|
+ user="jsmith")
|
||||||
|
+ assert 'member_user' not in cmd
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/remove_member_group.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_add_permission(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that permission is added
|
||||||
|
+ using api.Command["permission_add"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ cmd = api.Command["permission_add"]("Create users",
|
||||||
|
+ ipapermright='add', type='user')
|
||||||
|
+ assert 'Added permission "Create users"' in cmd['summary']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/add_perm.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_create_hbac_rule(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that hbac rule is added
|
||||||
|
+ using api.Command["hbacrule_add"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ cmd = api.Command["hbacrule_add"]("sshd_rule")
|
||||||
|
+ assert 'Added HBAC rule "sshd_rule"' in cmd['summary']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/add_hbac_rule.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_add_hbac_service(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that hbac service is added using
|
||||||
|
+ api.Command["hbacsvc_add"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ cmd = api.Command["hbacsvc_add"]("chronyd")
|
||||||
|
+ assert 'Added HBAC service "chronyd"' in cmd['summary']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/add_hbac_svc.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_enable_hbac_rule(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that hbac rule is enabled using
|
||||||
|
+ api.Command["hbacrule_enable"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ cmd = api.Command["hbacrule_enable"]("sshd_rule")
|
||||||
|
+ assert 'Enabled HBAC rule "sshd_rule"' in cmd['summary']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/enable_hbacrule.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_create_sudo_rule(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that sudo rule is created using
|
||||||
|
+ api.Command["sudorule_add"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ cmd = api.Command["sudorule_add"]("timechange")
|
||||||
|
+ assert 'Added Sudo Rule "timechange"' in cmd['summary']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/create_sudos.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_add_user_certificate(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks user certificate is added using
|
||||||
|
+ api.Command["user_add_cert"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ msg = 'Added certificates to user "jsmith"'
|
||||||
|
+ cmd = api.Command["user_add_cert"]("jsmith", usercertificate={CERT})
|
||||||
|
+ assert msg in cmd["summary"]
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/add_cert.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_remove_user_certificate(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that user certificate is removed
|
||||||
|
+ using api.Command["user_remove_cert"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ msg = 'Removed certificates from user "jsmith"'
|
||||||
|
+ cmd = api.Command["user_remove_cert"]("jsmith", usercertificate={CERT})
|
||||||
|
+ assert msg in cmd["summary"]
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/remove_cert.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_certmaprule_add(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that certmap rule is added using
|
||||||
|
+ api.Command["certmaprule_add"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ msg = ('Added Certificate Identity Mapping Rule "testrule"')
|
||||||
|
+ cmd = api.Command["certmaprule_add"]("testrule")
|
||||||
|
+ assert msg in cmd['summary']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/certmap_rule_add.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_certmaprule_enable(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that certmap rule is enabled
|
||||||
|
+ using api.Command["certmaprule_enable"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ msg = ('Enabled Certificate Identity Mapping Rule "testrule"')
|
||||||
|
+ cmd = api.Command["certmaprule_enable"]("testrule")
|
||||||
|
+ assert msg in cmd["summary"]
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/certmap_rule_enable.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_certmaprule_disable(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that certmap rule is disabled using
|
||||||
|
+ api.Command["certmaprule_disable"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ msg = ('Disabled Certificate Identity Mapping Rule "testrule"')
|
||||||
|
+ cmd = api.Command["certmaprule_disable"]("testrule")
|
||||||
|
+ assert msg in cmd["summary"]
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/certmap_rule_disable.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_certmaprule_del(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that certmap rule is deleted using
|
||||||
|
+ api.Command["certmaprule_del"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ msg = ('Deleted Certificate Identity Mapping Rule "testrule"')
|
||||||
|
+ cmd = api.Command["certmaprule_del"]("testrule")
|
||||||
|
+ assert msg in cmd['summary']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/certmap_rule_del.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_add_role(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that role and privilege is added using
|
||||||
|
+ api.Command["role_add"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ cmd1 = api.Command["role_add"]("junioradmin",
|
||||||
|
+ description="Junior admin")
|
||||||
|
+ assert 'Added role "junioradmin"' in cmd1["summary"]
|
||||||
|
+ cmd2 = api.Command.role_add_privilege("junioradmin",
|
||||||
|
+ privilege="Vault Administrators")["result"]
|
||||||
|
+ assert 'Vault Administrators' in cmd2["memberof_privilege"]
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/add_role.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_add_subid(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that subid is added for IPA user
|
||||||
|
+ using api.Command["subid_add"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ cmd = api.Command["subid_add"](ipaowner="jsmith")
|
||||||
|
+ assert 'Added subordinate id ' in cmd['summary']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/add_subid.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_add_otptoken(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that otp token is added for IPA user
|
||||||
|
+ using api.Command["otptoken_add"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ cmd = api.Command["otptoken_add"](
|
||||||
|
+ type='HOTP', description='testotp',
|
||||||
|
+ ipatokenotpalgorithm='sha512', ipatokenowner='jsmith',
|
||||||
|
+ ipatokenotpdigits='6')
|
||||||
|
+ assert 'Added OTP token' in cmd['summary']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/add_otptoken.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_user_del(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that user is deleted
|
||||||
|
+ using api.Command["user_del"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ cmd = api.Command["user_del"]("jsmith")
|
||||||
|
+ assert 'Deleted user "jsmith"' in cmd['summary']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/user_del.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_remove_ipa_group(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that group is removed
|
||||||
|
+ using api.Command["group_del"]
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ cmd = api.Command["group_del"]("developers")
|
||||||
|
+ assert 'Deleted group "developers"' in cmd['summary']
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/show_group.py", user_code_script
|
||||||
|
+ )
|
||||||
|
+
|
||||||
|
+ def test_batch_command(self):
|
||||||
|
+ """
|
||||||
|
+ This test checks that batch commands
|
||||||
|
+ can be run using api.
|
||||||
|
+ """
|
||||||
|
+ user_code_script = textwrap.dedent(
|
||||||
|
+ f"""
|
||||||
|
+ {API_INIT}
|
||||||
|
+ batch_args = []
|
||||||
|
+ for i in range(5):
|
||||||
|
+ user_id = "user%i" % i
|
||||||
|
+ args = [user_id]
|
||||||
|
+ kw = {{'givenname' : user_id, 'sn' : user_id}}
|
||||||
|
+ batch_args.append({{'method' : 'user_add', 'params' : [args, kw]}})
|
||||||
|
+ api.Command["batch"](*batch_args)
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
+ self.create_and_run_script(
|
||||||
|
+ "/tmp/batch.py", user_code_script
|
||||||
|
+ )
|
||||||
|
--
|
||||||
|
2.41.0
|
||||||
|
|
45
SOURCES/0024-ipatests-fixture-can-produce-IndexError.patch
Normal file
45
SOURCES/0024-ipatests-fixture-can-produce-IndexError.patch
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
From f816b4d9e6ff7a47b0da1a368d2454add78af07c Mon Sep 17 00:00:00 2001
|
||||||
|
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
Date: Fri, 11 Aug 2023 09:10:30 +0200
|
||||||
|
Subject: [PATCH] ipatests: fixture can produce IndexError
|
||||||
|
|
||||||
|
The fixture issue_and_expire_acme_cert returns a function
|
||||||
|
that fills the hosts array. If the function is not called in
|
||||||
|
the test (for instance because a test is skipped, as in
|
||||||
|
TestACMEPrune::test_prune_cert_search_size_limit), hosts = []
|
||||||
|
and hosts[0] raises an IndexError.
|
||||||
|
|
||||||
|
Fix the fixture to check first that hosts is not empty.
|
||||||
|
|
||||||
|
Related: https://pagure.io/freeipa/issue/9348
|
||||||
|
|
||||||
|
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
Reviewed-By: Mohammad Rizwan Yusuf <myusuf@redhat.com>
|
||||||
|
---
|
||||||
|
ipatests/test_integration/test_acme.py | 10 +++++++---
|
||||||
|
1 file changed, 7 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/ipatests/test_integration/test_acme.py b/ipatests/test_integration/test_acme.py
|
||||||
|
index c7389732cd067d49541cd04ea6687a6b95b4669f..bc989a9a2a00b0ac68b9dcffd4ccea269314961b 100644
|
||||||
|
--- a/ipatests/test_integration/test_acme.py
|
||||||
|
+++ b/ipatests/test_integration/test_acme.py
|
||||||
|
@@ -633,9 +633,13 @@ def issue_and_expire_acme_cert():
|
||||||
|
tasks.move_date(host, 'start', '-90days-60minutes')
|
||||||
|
|
||||||
|
# restart ipa services as date moved and wait to get things settle
|
||||||
|
- time.sleep(10)
|
||||||
|
- hosts[0].run_command(['ipactl', 'restart'])
|
||||||
|
- time.sleep(10)
|
||||||
|
+ # if the internal fixture was not called (for instance because the test
|
||||||
|
+ # was skipped), hosts = [] and hosts[0] would produce an IndexError
|
||||||
|
+ # exception.
|
||||||
|
+ if hosts:
|
||||||
|
+ time.sleep(10)
|
||||||
|
+ hosts[0].run_command(['ipactl', 'restart'])
|
||||||
|
+ time.sleep(10)
|
||||||
|
|
||||||
|
|
||||||
|
class TestACMERenew(IntegrationTest):
|
||||||
|
--
|
||||||
|
2.41.0
|
||||||
|
|
@ -0,0 +1,42 @@
|
|||||||
|
From 4a62a21499a4884f0db55d01966a6ff532a4ed1e Mon Sep 17 00:00:00 2001
|
||||||
|
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
Date: Mon, 14 Aug 2023 10:53:05 +0200
|
||||||
|
Subject: [PATCH] Installer: activate nss and pam services in sssd.conf
|
||||||
|
|
||||||
|
If there is already a sssd.conf file before the installer is
|
||||||
|
executed, the nss and pam services may not be enabled by the
|
||||||
|
installer. This happens for instance if the machine is hardened
|
||||||
|
for STIG and sssd.conf does not define services=... in the
|
||||||
|
[sssd] section.
|
||||||
|
|
||||||
|
The consequence is that trust cannot be established with an AD
|
||||||
|
domain.
|
||||||
|
|
||||||
|
The installer must enable nss and pam services even if there is
|
||||||
|
a pre-existing sssd.conf file.
|
||||||
|
|
||||||
|
Fixes: https://pagure.io/freeipa/issue/9427
|
||||||
|
|
||||||
|
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||||
|
---
|
||||||
|
ipaclient/install/client.py | 3 +++
|
||||||
|
1 file changed, 3 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py
|
||||||
|
index ef29a2c8a3f673860cb22e0e6953853fd96a8572..07d62a748f77e990a38e28e3675abb05eef0da8d 100644
|
||||||
|
--- a/ipaclient/install/client.py
|
||||||
|
+++ b/ipaclient/install/client.py
|
||||||
|
@@ -969,6 +969,9 @@ def configure_sssd_conf(
|
||||||
|
nss_service.set_option('memcache_timeout', 600)
|
||||||
|
sssdconfig.save_service(nss_service)
|
||||||
|
|
||||||
|
+ sssd_enable_service(sssdconfig, 'nss')
|
||||||
|
+ sssd_enable_service(sssdconfig, 'pam')
|
||||||
|
+
|
||||||
|
domain.set_option('ipa_domain', cli_domain)
|
||||||
|
domain.set_option('ipa_hostname', client_hostname)
|
||||||
|
if cli_domain.lower() != cli_realm.lower():
|
||||||
|
--
|
||||||
|
2.41.0
|
||||||
|
|
@ -1,16 +0,0 @@
|
|||||||
-----BEGIN PGP SIGNATURE-----
|
|
||||||
|
|
||||||
iQIzBAABCAAdFiEE11Z2TU1+KXxtrRFyaYdvcqbi008FAmN/lzsACgkQaYdvcqbi
|
|
||||||
00+f7w//a5Y4tgTD2A52fQdihv/Q2ZZqhPlSt8rP7bTLtGSjvANHpuF2u0FcjmtB
|
|
||||||
tADL4zljBGGMGONGt1qMF3d0BkAXhyVp8YNIBcL+abEhgeKL++3egOrI/8iyl4FB
|
|
||||||
Sr8Gvr1T4AJXjz+yZ/SsPNKerqFrJwi3flavZ7Bk1c2W2V3rJubSAvK9XwO7Cyxs
|
|
||||||
4afYpLAiknPh999q3zt7NyviivBTYXirif2T45Lelln9sQaB1ksqDA7oYYAfhV0B
|
|
||||||
wmUJMTtDoaMAcsLT29aC8wGSB5dttI5GmrF60gnbq/t5Tr+7x9ch8VYE60qkynU9
|
|
||||||
n1WcouuIwvcwfPpYSONak0vFrnMV2USNQj5OnzlKXl1HnHsSqoaQWRUA6bbBPjdb
|
|
||||||
xQLdQRrZiYtjG5YcwuZyg8TRP2ph1aY3yL2gAR1ZI13yJeNV0pwU+IwouJDiVPvS
|
|
||||||
dwiG8en1jUxYCeXFKjPX3A8/2ei+LvLTVY65qZKT+BsXyE2CymmUx7P20lFN5Ksb
|
|
||||||
RN+g37mJI8CwqmlemdTZiF+wJnlswS9SOS5zxhpVRiJHAV1sfxu66515c9+n890A
|
|
||||||
Hlm9sZn9UBQN5nLwuak8jaOr73E+d8uieXsSCA4wTtXKQSJs67fNY6ldeUmNximc
|
|
||||||
fq6Yh+lDau14rDlPZUkXx0Jd/oPEWDrtnJzfHECeoRn3KoNzezU=
|
|
||||||
=pxPY
|
|
||||||
-----END PGP SIGNATURE-----
|
|
16
SOURCES/freeipa-4.10.2.tar.gz.asc
Normal file
16
SOURCES/freeipa-4.10.2.tar.gz.asc
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
-----BEGIN PGP SIGNATURE-----
|
||||||
|
|
||||||
|
iQIzBAABCAAdFiEE11Z2TU1+KXxtrRFyaYdvcqbi008FAmR+6S4ACgkQaYdvcqbi
|
||||||
|
008kvQ/9HuW6rWRJPY9/bqfaaeTKAT9JPCdq6jwDj7rSxpzJRE2r8vuwL3XxvXEa
|
||||||
|
8qW3qwx4qcBV3hrOPX3annilCgfyUN0ayF72rfDxGmVzTifooEVd0mmaDJOd9JHy
|
||||||
|
wLVYbImvsitC59luFF/XTIx5Xgo8Msu7BtAC5Tf5+mws0/i6ZxmyufYBPEmydgVM
|
||||||
|
jdpVSZfq4hd4HwfYH0Ej5c8sWfv2OTTENyBWn5x9LiWvC6rJi42u7ubcnWoCi6If
|
||||||
|
kXzJCRf7JTDzDvmMDVZMoTJCQa0EwlST7Yr9V7rLJViUGDwqxVO7VoeQi2WoV5PN
|
||||||
|
zDSoLoCVEgLdDt0EAYRlBxPzoe65kNBdGFhC3eT0uIO676NZuTMVEXaRtId1wfnU
|
||||||
|
o52xx3r5OPvRrjRLhKsAsMSiqX0Cr/wgH1L8QuSpriM1gMO6jZTkFpGtjD1XEvWd
|
||||||
|
VsiSVqR0y+E8U3bkLOTHvByPvWk9QlmN0e6WDyV0FvGPaPlD2VCGNLqraldeEKvr
|
||||||
|
wQxVvMWMqX+CKs2ZWYlzfgzFd0ZlUfsYhTcDaliJIh5Tcn5Ow+CSX/vWMXS6Msyh
|
||||||
|
80fS5k7NswIsa3bA0QSoFpAcSkNxxovKyIWpXamL/MgX/nqZqJE74aUtchANl9jd
|
||||||
|
j5yAU2s4eUuvbTMQkQjEJHl97a/jjGCGKnCunF/RO3WLaGdi9Dk=
|
||||||
|
=Bq0h
|
||||||
|
-----END PGP SIGNATURE-----
|
@ -178,7 +178,7 @@
|
|||||||
# RHEL 8.2+, F32+ has 3.58
|
# RHEL 8.2+, F32+ has 3.58
|
||||||
%global nss_version 3.44.0-4
|
%global nss_version 3.44.0-4
|
||||||
|
|
||||||
%define krb5_base_version %(LC_ALL=C /usr/bin/pkgconf --modversion krb5 | grep -Eo '^[^.]+\.[^.]+' || echo %krb5_version)
|
%define krb5_base_version %(LC_ALL=C /usr/bin/pkgconf --modversion krb5 2>/dev/null | grep -Eo '^[^.]+\.[^.]+' || echo %krb5_version)
|
||||||
%global kdcproxy_version 0.4-3
|
%global kdcproxy_version 0.4-3
|
||||||
|
|
||||||
%if 0%{?fedora} >= 33 || 0%{?rhel} >= 9
|
%if 0%{?fedora} >= 33 || 0%{?rhel} >= 9
|
||||||
@ -210,7 +210,7 @@
|
|||||||
|
|
||||||
# Work-around fact that RPM SPEC parser does not accept
|
# Work-around fact that RPM SPEC parser does not accept
|
||||||
# "Version: @VERSION@" in freeipa.spec.in used for Autoconf string replacement
|
# "Version: @VERSION@" in freeipa.spec.in used for Autoconf string replacement
|
||||||
%define IPA_VERSION 4.10.1
|
%define IPA_VERSION 4.10.2
|
||||||
# Release candidate version -- uncomment with one percent for RC versions
|
# Release candidate version -- uncomment with one percent for RC versions
|
||||||
#%%global rc_version %%nil
|
#%%global rc_version %%nil
|
||||||
%define AT_SIGN @
|
%define AT_SIGN @
|
||||||
@ -223,10 +223,10 @@
|
|||||||
|
|
||||||
Name: %{package_name}
|
Name: %{package_name}
|
||||||
Version: %{IPA_VERSION}
|
Version: %{IPA_VERSION}
|
||||||
Release: 6%{?rc_version:.%rc_version}%{?dist}
|
Release: 4%{?rc_version:.%rc_version}%{?dist}
|
||||||
Summary: The Identity, Policy and Audit system
|
Summary: The Identity, Policy and Audit system
|
||||||
|
|
||||||
License: GPLv3+
|
License: GPL-3.0-or-later
|
||||||
URL: http://www.freeipa.org/
|
URL: http://www.freeipa.org/
|
||||||
Source0: https://releases.pagure.org/freeipa/freeipa-%{version}%{?rc_version}.tar.gz
|
Source0: https://releases.pagure.org/freeipa/freeipa-%{version}%{?rc_version}.tar.gz
|
||||||
# Only use detached signature for the distribution builds. If it is a developer build, skip it
|
# Only use detached signature for the distribution builds. If it is a developer build, skip it
|
||||||
@ -247,28 +247,31 @@ Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch
|
|||||||
Patch1002: 1002-Revert-freeipa.spec-depend-on-bind-dnssec-utils.patch
|
Patch1002: 1002-Revert-freeipa.spec-depend-on-bind-dnssec-utils.patch
|
||||||
%endif
|
%endif
|
||||||
%if 0%{?rhel} == 9
|
%if 0%{?rhel} == 9
|
||||||
Patch0001: 0001-updates-fix-memberManager-ACI-to-allow-managers-from.patch
|
Patch0001: 0001-webuitests-close-notification-which-hides-Add-button.patch
|
||||||
Patch0002: 0002-Spec-file-ipa-client-depends-on-krb5-pkinit-openssl.patch
|
Patch0002: 0002-ipatests-Check-that-SSSD_PUBCONF_KRB5_INCLUDE_D_DIR-.patch
|
||||||
Patch0003: 0003-server-install-remove-error-log-about-missing-bkup-f.patch
|
Patch0003: 0003-Revert-Use-the-OpenSSL-certificate-parser-in-cert-fi.patch
|
||||||
Patch0004: 0004-ipa-tests-Add-LANG-before-kinit-command-to-fix-issue.patch
|
Patch0004: 0004-Revert-cert_find-fix-call-with-all.patch
|
||||||
Patch0005: 0005-trust-add-handle-missing-msSFU30MaxGidNumber.patch
|
Patch0005: 0005-Use-the-python-cryptography-parser-directly-in-cert-.patch
|
||||||
Patch0006: 0006-doc-Design-for-certificate-pruning.patch
|
Patch0006: 0006-Upgrade-add-PKI-drop-in-file-if-missing.patch
|
||||||
Patch0007: 0007-ipa-acme-manage-add-certificate-request-pruning-mana.patch
|
Patch0007: 0007-Integration-test-add-a-test-for-upgrade-and-PKI-drop.patch
|
||||||
Patch0008: 0008-doc-add-the-run-command-for-manual-job-execution.patch
|
Patch0008: 0008-Uninstaller-uninstall-PKI-before-shutting-down-servi.patch
|
||||||
Patch0009: 0009-tests-add-wrapper-around-ACME-RSNv3-test.patch
|
Patch0009: 0009-Detection-of-PKI-subsystem.patch
|
||||||
Patch0010: 0010-automember-rebuild-add-a-notice-about-high-CPU-usage.patch
|
Patch0010: 0010-Upgrade-fix-replica-agreement.patch
|
||||||
Patch0011: 0011-Fix-setting-values-of-0-in-ACME-pruning.patch
|
Patch0011: 0011-Integration-tests-add-a-test-to-ipa-server-upgrade.patch
|
||||||
Patch0012: 0012-Wipe-the-ipa-ca-DNS-record-when-updating-system-reco.patch
|
Patch0012: 0012-tests-fix-backup-restore-scenario-with-replica.patch
|
||||||
Patch0013: 0013-ipa-kdb-PAC-consistency-checker-needs-to-handle-chil.patch
|
Patch0013: 0013-OTP-fix-data-type-to-avoid-endianness-issue.patch
|
||||||
Patch0014: 0014-Add-test-for-SSH-with-GSSAPI-auth.patch
|
Patch0014: 0014-ipatests-enable-firewall-rule-for-http-service-on-ac.patch
|
||||||
Patch0015: 0015-webui-tests-fix-assertion-in-test_subid.py.patch
|
Patch0015: 0015-User-plugin-improve-error-related-to-non-existing-id.patch
|
||||||
Patch0016: 0016-ipatests-mark-test_smb-as-xfail.patch
|
Patch0016: 0016-xmlrpc-tests-add-a-test-for-user-plugin-with-non-exi.patch
|
||||||
Patch0017: 0017-Tests-force-key-type-in-ACME-tests.patch
|
Patch0017: 0017-Fix-memory-leak-in-the-OTP-last-token-plugin.patch
|
||||||
Patch0018: 0018-tests-Add-ipa_ca_name-checking-to-DNS-system-records.patch
|
Patch0018: 0018-Prevent-the-admin-user-from-being-deleted.patch
|
||||||
Patch0019: 0019-tests-Add-new-ipa-ca-error-messages-to-IPADNSSystemR.patch
|
Patch0019: 0019-ipa-kdb-fix-error-handling-of-is_master_host.patch
|
||||||
Patch0020: 0020-ipatests-tests-for-certificate-pruning.patch
|
Patch0020: 0020-ipatests-update-expected-webui-msg-for-admin-deletio.patch
|
||||||
Patch0021: 0021-ipatests-ensure-that-ipa-automember-rebuild-prints-a.patch
|
Patch0021: 0021-ipatests-remove-fixture-call-and-wait-to-get-things-.patch
|
||||||
Patch0022: 0022-ipatests-fix-tests-in-TestACMEPrune.patch
|
Patch0022: 0022-ipatests-fix-test_topology.patch
|
||||||
|
Patch0023: 0023-ipatests-idm-api-related-tests.patch
|
||||||
|
Patch0024: 0024-ipatests-fixture-can-produce-IndexError.patch
|
||||||
|
Patch0025: 0025-Installer-activate-nss-and-pam-services-in-sssd.conf.patch
|
||||||
Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch
|
Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch
|
||||||
%endif
|
%endif
|
||||||
%endif
|
%endif
|
||||||
@ -319,7 +322,12 @@ BuildRequires: libpwquality-devel
|
|||||||
BuildRequires: libsss_idmap-devel
|
BuildRequires: libsss_idmap-devel
|
||||||
BuildRequires: libsss_certmap-devel
|
BuildRequires: libsss_certmap-devel
|
||||||
BuildRequires: libsss_nss_idmap-devel >= %{sssd_version}
|
BuildRequires: libsss_nss_idmap-devel >= %{sssd_version}
|
||||||
|
%if 0%{?fedora} >= 39 || 0%{?rhel} >= 10
|
||||||
|
# Do not use nodejs20 on fedora < 39, https://pagure.io/freeipa/issue/9374
|
||||||
BuildRequires: nodejs(abi)
|
BuildRequires: nodejs(abi)
|
||||||
|
%else
|
||||||
|
BuildRequires: nodejs(abi) < 111
|
||||||
|
%endif
|
||||||
# use old dependency on RHEL 8 for now
|
# use old dependency on RHEL 8 for now
|
||||||
%if 0%{?fedora} >= 31 || 0%{?rhel} >= 9
|
%if 0%{?fedora} >= 31 || 0%{?rhel} >= 9
|
||||||
BuildRequires: python3-rjsmin
|
BuildRequires: python3-rjsmin
|
||||||
@ -500,7 +508,7 @@ Requires: policycoreutils >= 2.1.12-5
|
|||||||
Requires: tar
|
Requires: tar
|
||||||
Requires(pre): certmonger >= %{certmonger_version}
|
Requires(pre): certmonger >= %{certmonger_version}
|
||||||
Requires(pre): 389-ds-base >= %{ds_version}
|
Requires(pre): 389-ds-base >= %{ds_version}
|
||||||
Requires: fontawesome-fonts
|
Requires: font(fontawesome)
|
||||||
Requires: open-sans-fonts
|
Requires: open-sans-fonts
|
||||||
%if 0%{?fedora} >= 32 || 0%{?rhel} >= 9
|
%if 0%{?fedora} >= 32 || 0%{?rhel} >= 9
|
||||||
# https://pagure.io/freeipa/issue/8632
|
# https://pagure.io/freeipa/issue/8632
|
||||||
@ -714,6 +722,7 @@ Requires: jansson
|
|||||||
%endif
|
%endif
|
||||||
Requires: sssd-ipa >= %{sssd_version}
|
Requires: sssd-ipa >= %{sssd_version}
|
||||||
Requires: sssd-idp >= %{sssd_version}
|
Requires: sssd-idp >= %{sssd_version}
|
||||||
|
Requires: sssd-krb5 >= %{sssd_version}
|
||||||
Requires: certmonger >= %{certmonger_version}
|
Requires: certmonger >= %{certmonger_version}
|
||||||
Requires: nss-tools >= %{nss_version}
|
Requires: nss-tools >= %{nss_version}
|
||||||
Requires: bind-utils
|
Requires: bind-utils
|
||||||
@ -1259,10 +1268,8 @@ if [ $1 -gt 1 ] ; then
|
|||||||
test -f '/var/lib/ipa-client/sysrestore/sysrestore.index' && restore=$(wc -l '/var/lib/ipa-client/sysrestore/sysrestore.index' | awk '{print $1}')
|
test -f '/var/lib/ipa-client/sysrestore/sysrestore.index' && restore=$(wc -l '/var/lib/ipa-client/sysrestore/sysrestore.index' | awk '{print $1}')
|
||||||
|
|
||||||
if [ -f '/etc/sssd/sssd.conf' -a $restore -ge 2 ]; then
|
if [ -f '/etc/sssd/sssd.conf' -a $restore -ge 2 ]; then
|
||||||
if ! grep -E -q '/var/lib/sss/pubconf/krb5.include.d/' /etc/krb5.conf 2>/dev/null ; then
|
if grep -E -q '/var/lib/sss/pubconf/krb5.include.d/' /etc/krb5.conf 2>/dev/null ; then
|
||||||
echo "includedir /var/lib/sss/pubconf/krb5.include.d/" > /etc/krb5.conf.ipanew
|
sed -i '\;includedir /var/lib/sss/pubconf/krb5.include.d;d' /etc/krb5.conf
|
||||||
cat /etc/krb5.conf >> /etc/krb5.conf.ipanew
|
|
||||||
mv -Z /etc/krb5.conf.ipanew /etc/krb5.conf
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -1756,6 +1763,35 @@ fi
|
|||||||
%endif
|
%endif
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Thu Aug 17 2023 Florence Blanc-Renaud <flo@redhat.com> - 4.10.2-4
|
||||||
|
- Resolves: rhbz#2231847 RHEL 8.8 & 9.2 fails to create AD trust with STIG applied
|
||||||
|
- Resolves: rhbz#2232056 Include latest test fixes in python3-ipatests
|
||||||
|
|
||||||
|
* Thu Aug 10 2023 Florence Blanc-Renaud <flo@redhat.com> - 4.10.2-3
|
||||||
|
- Resolves: rhbz#2229712 Delete operation protection for admin user
|
||||||
|
- Resolves: rhbz#2227831 Interrupt request processing in ipadb_fill_info3() if connection to 389ds is lost
|
||||||
|
- Resolves: rhbz#2227784 libipa_otp_lasttoken plugin memory leak
|
||||||
|
- Resolves: rhbz#2224570 Improved error messages are needed when attempting to add a non-existing idp to a user
|
||||||
|
- Resolves: rhbz#2230251 Backport latest test fixes to python3-ipatests
|
||||||
|
|
||||||
|
* Thu Jun 29 2023 Florence Blanc-Renaud <flo@redhat.com> - 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 <flo@redhat.com> - 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
|
||||||
|
- Resolves: rhbz#2192625 Better catch of the IPA web UI event "IPA Error 4301:CertificateOperationError", and IPA httpd error CertificateOperationError
|
||||||
|
- Resolves: rhbz#2188567 IPA client Kerberos configuration incompatible with java
|
||||||
|
- Resolves: rhbz#2182683 Tolerate absence of PAC ticket signature depending of domain and servers capabilities [rhel-9]
|
||||||
|
- Resolves: rhbz#2180914 Sequence processing failures for group_add using server context
|
||||||
|
- Resolves: rhbz#2165880 Add RBCD support to IPA
|
||||||
|
- Resolves: rhbz#2160399 get_ranges - [file ipa_sidgen_common.c, line 276]: Failed to convert LDAP entry to range struct
|
||||||
|
|
||||||
* Wed Feb 22 2023 Florence Blanc-Renaud <flo@redhat.com> - 4.10.1-6
|
* Wed Feb 22 2023 Florence Blanc-Renaud <flo@redhat.com> - 4.10.1-6
|
||||||
- Resolves: rhbz#2169632 Backport latest test fixes in python3-ipatests
|
- Resolves: rhbz#2169632 Backport latest test fixes in python3-ipatests
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user