import CS ipa-4.10.2-4.el9_3

This commit is contained in:
eabdullin 2023-11-07 13:16:55 +00:00
parent 704e3549ca
commit db83624e48
54 changed files with 2422 additions and 3675 deletions

2
.gitignore vendored
View File

@ -1 +1 @@
SOURCES/freeipa-4.10.1.tar.gz
SOURCES/freeipa-4.10.2.tar.gz

View File

@ -1 +1 @@
6203cf7c2e003c35eb9ac40e4fd2954c6bea1856 SOURCES/freeipa-4.10.1.tar.gz
17d580b7dccb1586898aa46c7ecdd2bd2754ee5f SOURCES/freeipa-4.10.2.tar.gz

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View File

@ -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

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View File

@ -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

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View File

@ -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

View File

@ -1,574 +0,0 @@
From 51c378f66fcf59322a0774a6d9b37e7e9ac55a17 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Fri, 7 Apr 2023 17:04:06 +0200
Subject: [PATCH] Tolerate absence of PAC ticket signature depending of server
capabilities
Since November 2020, Active Directory KDC generates a new type of
signature as part of the PAC. It is called "ticket signature", and is
generated based on the encrypted part of the ticket. The presence of
this signature is not mandatory in order for the PAC to be accepted for
S4U requests.
However, the behavior is different for MIT krb5. Support was added as
part of the 1.20 release, and this signature is required in order to
process S4U requests. Contrary to the PAC extended KDC signature, the
code generating this signature cannot be isolated and backported to
older krb5 versions because this version of the KDB API does not allow
passing the content of the ticket's encrypted part to IPA.
This is an issue in gradual upgrade scenarios where some IPA servers
rely on 1.19 and older versions of MIT krb5, while others use version
1.20 or newer. A service ticket that was provided by 1.19- IPA KDC will
be rejected when used by a service against a 1.20+ IPA KDC for S4U
requests.
On Fedora, CentOS 9 Stream, and RHEL 9, when the krb5 version is 1.20 or
newer, it will include a downstream-only update adding the
"optional_pac_tkt_chksum" KDB string attribute allowing to tolerate the
absence of PAC ticket signatures, if necessary.
This commit adds an extra step during the installation and update
processes where it adds a "pacTktSignSupported" ipaConfigString
attribute in "cn=KDC,cn=[server],cn=masters,cn=ipa,cn=etc,[basedn]" if
the MIT krb5 version IPA what built with was 1.20 or newer.
This commit also set "optional_pac_tkt_chksum" as a virtual KDB entry
attribute. This means the value of the attribute is not actually stored
in the database (to avoid race conditions), but its value is determined
at the KDC starting time by search the "pacTktSignSupported"
ipaConfigString in the server list. If this value is missing for at
least of them is missing, enforcement of the PAC ticket signature is
disabled by setting "optional_pac_tkt_chksum" to true for the local
realm TGS KDB entry.
For foreign realm TGS KDB entries, the "optional_pac_tkt_chksum" virtual
string attribute is set to true systematically, because, at least for
now, trusted AD domains can still have PAC ticket signature support
disabled.
Given the fact the "pacTktSignSupported" ipaConfigString for a single
server is added when this server is updated, and that the value of
"optional_pac_tkt_chksum" is determined at KDC starting time based on
the ipaConfigString attributes of all the KDCs in the domain, this
requires to restart all the KDCs in the domain after all IPA servers
were updated in order for PAC ticket signature enforcement to actually
take effect.
Fixes: https://pagure.io/freeipa/issue/9371
Signed-off-by: Julien Rische <jrische@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
(cherry picked from commit bbe545ff9feb972e549c743025e4a26b14ef8f89)
---
VERSION.m4 | 6 ++
configure.ac | 1 +
daemons/ipa-kdb/ipa_kdb.c | 55 +++++++++++
daemons/ipa-kdb/ipa_kdb.h | 1 +
daemons/ipa-kdb/ipa_kdb_principals.c | 139 +++++++++++++++++++++++----
ipapython/Makefile.am | 15 +--
ipapython/version.py.in | 4 +
ipaserver/install/krbinstance.py | 25 ++++-
ipaserver/install/server/upgrade.py | 5 +
ipaserver/masters.py | 2 +
10 files changed, 225 insertions(+), 28 deletions(-)
diff --git a/VERSION.m4 b/VERSION.m4
index e5d60c4c3..9b727feca 100644
--- a/VERSION.m4
+++ b/VERSION.m4
@@ -137,6 +137,11 @@ ifelse(IPA_VERSION_IS_GIT_SNAPSHOT, yes,
IPA_GIT_VERSION),
NEWLINE)) dnl IPA_VERSION end
+########################################################
+# Version of MIT krb5 used to build IPA
+########################################################
+define(IPA_KRB5_BUILD_VERSION, translit(esyscmd(krb5-config --version | awk '{ print $NF }'), NEWLINE))
+
dnl DEBUG: uncomment following lines and run command m4 VERSION.m4
dnl `IPA_VERSION: ''IPA_VERSION'
dnl `IPA_GIT_VERSION: ''IPA_GIT_VERSION'
@@ -144,3 +149,4 @@ dnl `IPA_GIT_BRANCH: ''IPA_GIT_BRANCH'
dnl `IPA_API_VERSION: ''IPA_API_VERSION'
dnl `IPA_DATA_VERSION: ''IPA_DATA_VERSION'
dnl `IPA_NUM_VERSION: ''IPA_NUM_VERSION'
+dnl `IPA_KRB5_BUILD_VERSION: ''IPA_KRB5_BUILD_VERSION'
diff --git a/configure.ac b/configure.ac
index 140045821..973cba33c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -460,6 +460,7 @@ AC_SUBST(VENDOR_SUFFIX)
AC_SUBST([VERSION], [IPA_VERSION])
AC_SUBST([GIT_VERSION], [IPA_GIT_VERSION])
AC_SUBST([GIT_BRANCH], [IPA_GIT_BRANCH])
+AC_SUBST([KRB5_BUILD_VERSION], [IPA_KRB5_BUILD_VERSION])
# used by Makefile.am for files depending on templates
AC_SUBST([CONFIG_STATUS])
diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c
index 93563536c..9a56640ff 100644
--- a/daemons/ipa-kdb/ipa_kdb.c
+++ b/daemons/ipa-kdb/ipa_kdb.c
@@ -524,6 +524,52 @@ static krb5_principal ipadb_create_local_tgs(krb5_context kcontext,
return tgtp;
}
+static char *no_attrs[] = {
+ LDAP_NO_ATTRS,
+
+ NULL
+};
+
+static krb5_error_code
+should_support_pac_tkt_sign(krb5_context kcontext, bool *result)
+{
+ struct ipadb_context *ipactx;
+ krb5_error_code kerr;
+ LDAPMessage *res = NULL;
+ char *masters_dn = NULL;
+ int count;
+
+ char *kdc_filter = "(&(cn=KDC)(objectClass=ipaConfigObject)"
+ "(!(ipaConfigString=pacTktSignSupported)))";
+
+ ipactx = ipadb_get_context(kcontext);
+ if (!ipactx) {
+ kerr = KRB5_KDB_DBNOTINITED;
+ goto done;
+ }
+
+ count = asprintf(&masters_dn, "cn=masters,cn=ipa,cn=etc,%s", ipactx->base);
+ if (count < 0) {
+ kerr = ENOMEM;
+ goto done;
+ }
+
+ kerr = ipadb_simple_search(ipactx, masters_dn, LDAP_SCOPE_SUBTREE,
+ kdc_filter, no_attrs, &res);
+ if (kerr)
+ goto done;
+
+ count = ldap_count_entries(ipactx->lcontext, res);
+
+ if (result)
+ *result = (count == 0);
+
+done:
+ free(masters_dn);
+ ldap_msgfree(res);
+ return kerr;
+}
+
/* INTERFACE */
static krb5_error_code ipadb_init_library(void)
@@ -544,6 +590,7 @@ static krb5_error_code ipadb_init_module(krb5_context kcontext,
krb5_error_code kerr;
int ret;
int i;
+ bool pac_tkt_sign_supported;
/* make sure the context is freed to avoid leaking it */
ipactx = ipadb_get_context(kcontext);
@@ -628,6 +675,14 @@ static krb5_error_code ipadb_init_module(krb5_context kcontext,
goto fail;
}
+ /* Enforce PAC ticket signature verification if supported by all KDCs */
+ kerr = should_support_pac_tkt_sign(kcontext, &pac_tkt_sign_supported);
+ if (kerr) {
+ ret = kerr;
+ goto fail;
+ }
+ ipactx->optional_pac_tkt_chksum = !pac_tkt_sign_supported;
+
return 0;
fail:
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
index 7aa5be494..0f4d3e431 100644
--- a/daemons/ipa-kdb/ipa_kdb.h
+++ b/daemons/ipa-kdb/ipa_kdb.h
@@ -143,6 +143,7 @@ struct ipadb_context {
krb5_key_salt_tuple *def_encs;
int n_def_encs;
struct ipadb_mspac *mspac;
+ bool optional_pac_tkt_chksum;
#ifdef HAVE_KRB5_CERTAUTH_PLUGIN
krb5_certauth_moddata certauth_moddata;
#endif
diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c
index e95cb453c..e6c3fba21 100644
--- a/daemons/ipa-kdb/ipa_kdb_principals.c
+++ b/daemons/ipa-kdb/ipa_kdb_principals.c
@@ -113,6 +113,8 @@ static char *std_principal_obj_classes[] = {
#define DEFAULT_TL_DATA_CONTENT "\x00\x00\x00\x00principal@UNINITIALIZED"
+#define OPT_PAC_TKT_CHKSUM_STR_ATTR_NAME "optional_pac_tkt_chksum"
+
static int ipadb_ldap_attr_to_tl_data(LDAP *lcontext, LDAPMessage *le,
char *attrname,
krb5_tl_data **result, int *num)
@@ -178,10 +180,56 @@ done:
return ret;
}
-static krb5_error_code ipadb_set_tl_data(krb5_db_entry *entry,
- krb5_int16 type,
- krb5_ui_2 length,
- const krb5_octet *data)
+static bool
+is_tgs_princ(krb5_context kcontext, krb5_const_principal princ)
+{
+ krb5_data *primary;
+ size_t l_tgs_name;
+
+ if (2 != krb5_princ_size(kcontext, princ))
+ return false;
+
+ primary = krb5_princ_component(kcontext, princ, 0);
+
+ l_tgs_name = strlen(KRB5_TGS_NAME);
+
+ if (l_tgs_name != primary->length)
+ return false;
+
+ return 0 == memcmp(primary->data, KRB5_TGS_NAME, l_tgs_name);
+}
+
+static krb5_error_code
+cmp_local_tgs_princ(krb5_context kcontext, const char *local_realm,
+ krb5_const_principal princ, bool *result)
+{
+ krb5_principal local_tgs_princ;
+ size_t l_local_realm;
+ krb5_error_code kerr;
+ bool res;
+
+ l_local_realm = strlen(local_realm);
+
+ kerr = krb5_build_principal(kcontext, &local_tgs_princ,
+ l_local_realm, local_realm,
+ KRB5_TGS_NAME, local_realm, NULL);
+ if (kerr)
+ goto end;
+
+ res = (bool) krb5_principal_compare(kcontext, local_tgs_princ, princ);
+
+ if (result)
+ *result = res;
+
+end:
+ krb5_free_principal(kcontext, local_tgs_princ);
+ return kerr;
+}
+
+krb5_error_code ipadb_set_tl_data(krb5_db_entry *entry,
+ krb5_int16 type,
+ krb5_ui_2 length,
+ const krb5_octet *data)
{
krb5_error_code kerr;
krb5_tl_data *new_td = NULL;
@@ -1632,6 +1680,8 @@ krb5_error_code ipadb_get_principal(krb5_context kcontext,
krb5_db_entry **entry)
{
struct ipadb_context *ipactx;
+ bool is_local_tgs_princ;
+ const char *opt_pac_tkt_chksum_val;
krb5_error_code kerr;
*entry = NULL;
@@ -1647,11 +1697,33 @@ krb5_error_code ipadb_get_principal(krb5_context kcontext,
/* Lookup local names and aliases first. */
kerr = dbget_princ(kcontext, ipactx, search_for, flags, entry);
- if (kerr != KRB5_KDB_NOENTRY) {
+ if (kerr == KRB5_KDB_NOENTRY) {
+ kerr = dbget_alias(kcontext, ipactx, search_for, flags, entry);
+ }
+ if (kerr)
return kerr;
+
+ /* If TGS principal, some virtual attributes may be added */
+ if (is_tgs_princ(kcontext, (*entry)->princ)) {
+ kerr = cmp_local_tgs_princ(kcontext, ipactx->realm, (*entry)->princ,
+ &is_local_tgs_princ);
+ if (kerr)
+ return kerr;
+
+ /* PAC ticket signature should be optional for foreign realms, and local
+ * realm if not supported by all servers
+ */
+ if (!is_local_tgs_princ || ipactx->optional_pac_tkt_chksum)
+ opt_pac_tkt_chksum_val = "true";
+ else
+ opt_pac_tkt_chksum_val = "false";
+
+ kerr = krb5_dbe_set_string(kcontext, *entry,
+ OPT_PAC_TKT_CHKSUM_STR_ATTR_NAME,
+ opt_pac_tkt_chksum_val);
}
- return dbget_alias(kcontext, ipactx, search_for, flags, entry);
+ return kerr;
}
void ipadb_free_principal_e_data(krb5_context kcontext, krb5_octet *e_data)
@@ -1954,6 +2026,20 @@ done:
return kerr;
}
+static bool should_filter_out_attr(krb5_tl_data *data)
+{
+ switch (data->tl_data_type) {
+ case KRB5_TL_DB_ARGS:
+ case KRB5_TL_KADM_DATA:
+ case KRB5_TL_LAST_ADMIN_UNLOCK:
+ case KRB5_TL_LAST_PWD_CHANGE:
+ case KRB5_TL_MKVNO:
+ return true;
+ default:
+ return false;
+ }
+}
+
static krb5_error_code ipadb_get_ldap_mod_extra_data(struct ipadb_mods *imods,
krb5_tl_data *tl_data,
int mod_op)
@@ -1965,13 +2051,8 @@ static krb5_error_code ipadb_get_ldap_mod_extra_data(struct ipadb_mods *imods,
int n, i;
for (n = 0, data = tl_data; data; data = data->tl_data_next) {
- if (data->tl_data_type == KRB5_TL_LAST_PWD_CHANGE ||
- data->tl_data_type == KRB5_TL_KADM_DATA ||
- data->tl_data_type == KRB5_TL_DB_ARGS ||
- data->tl_data_type == KRB5_TL_MKVNO ||
- data->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK) {
+ if (should_filter_out_attr(data))
continue;
- }
n++;
}
@@ -1987,13 +2068,8 @@ static krb5_error_code ipadb_get_ldap_mod_extra_data(struct ipadb_mods *imods,
for (i = 0, data = tl_data; data; data = data->tl_data_next) {
- if (data->tl_data_type == KRB5_TL_LAST_PWD_CHANGE ||
- data->tl_data_type == KRB5_TL_KADM_DATA ||
- data->tl_data_type == KRB5_TL_DB_ARGS ||
- data->tl_data_type == KRB5_TL_MKVNO ||
- data->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK) {
+ if (should_filter_out_attr(data))
continue;
- }
be_type = htons(data->tl_data_type);
@@ -2745,10 +2821,37 @@ done:
return kerr;
}
+static krb5_error_code
+remove_virtual_str_attrs(krb5_context kcontext, krb5_db_entry *entry)
+{
+ char *str_attr_val;
+ krb5_error_code kerr;
+
+ kerr = krb5_dbe_get_string(kcontext, entry,
+ OPT_PAC_TKT_CHKSUM_STR_ATTR_NAME,
+ &str_attr_val);
+ if (kerr)
+ return kerr;
+
+ if (str_attr_val)
+ kerr = krb5_dbe_set_string(kcontext, entry,
+ OPT_PAC_TKT_CHKSUM_STR_ATTR_NAME,
+ NULL);
+
+ krb5_dbe_free_string(kcontext, str_attr_val);
+ return kerr;
+}
+
krb5_error_code ipadb_put_principal(krb5_context kcontext,
krb5_db_entry *entry,
char **db_args)
{
+ krb5_error_code kerr;
+
+ kerr = remove_virtual_str_attrs(kcontext, entry);
+ if (kerr)
+ return kerr;
+
if (entry->mask & KMASK_PRINCIPAL) {
return ipadb_add_principal(kcontext, entry);
} else {
diff --git a/ipapython/Makefile.am b/ipapython/Makefile.am
index 7038e8b57..6b336d8fe 100644
--- a/ipapython/Makefile.am
+++ b/ipapython/Makefile.am
@@ -13,11 +13,12 @@ bdist_wheel: version.py
$(AM_V_GEN)awk '$$1 == "default:" { print $$2 }' $< >$@
version.py: version.py.in .DEFAULT_PLUGINS $(top_builddir)/$(CONFIG_STATUS)
- $(AM_V_GEN)sed \
- -e 's|@API_VERSION[@]|$(API_VERSION)|g' \
- -e 's|@NUM_VERSION[@]|$(NUM_VERSION)|g' \
- -e 's|@VERSION[@]|$(VERSION)|g' \
- -e 's|@VENDOR_SUFFIX[@]|$(VENDOR_SUFFIX)|g' \
- -e '/@DEFAULT_PLUGINS[@]/r .DEFAULT_PLUGINS' \
- -e '/@DEFAULT_PLUGINS[@]/d' \
+ $(AM_V_GEN)sed \
+ -e 's|@API_VERSION[@]|$(API_VERSION)|g' \
+ -e 's|@NUM_VERSION[@]|$(NUM_VERSION)|g' \
+ -e 's|@VERSION[@]|$(VERSION)|g' \
+ -e 's|@VENDOR_SUFFIX[@]|$(VENDOR_SUFFIX)|g' \
+ -e 's|@KRB5_BUILD_VERSION[@]|$(KRB5_BUILD_VERSION)|g' \
+ -e '/@DEFAULT_PLUGINS[@]/r .DEFAULT_PLUGINS' \
+ -e '/@DEFAULT_PLUGINS[@]/d' \
$< > $@
diff --git a/ipapython/version.py.in b/ipapython/version.py.in
index 5a71fb8cf..a8f4218a7 100644
--- a/ipapython/version.py.in
+++ b/ipapython/version.py.in
@@ -17,6 +17,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
+from pkg_resources import parse_version
+
# The full version including strings
VERSION = "@VERSION@"
@@ -51,3 +53,5 @@ API_VERSION = "@API_VERSION@"
DEFAULT_PLUGINS = frozenset(l.strip() for l in """
@DEFAULT_PLUGINS@
""".strip().splitlines())
+
+KRB5_BUILD_VERSION = parse_version("@KRB5_BUILD_VERSION@")
diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py
index a5eaa7b17..acb7419d6 100644
--- a/ipaserver/install/krbinstance.py
+++ b/ipaserver/install/krbinstance.py
@@ -26,6 +26,7 @@ import socket
import dbus
import dns.name
+from pkg_resources import parse_version
from ipalib import x509
from ipalib.install import certstore
@@ -34,6 +35,7 @@ from ipaserver.install import installutils
from ipapython import ipaldap
from ipapython import ipautil
from ipapython import kernel_keyring
+from ipapython.version import KRB5_BUILD_VERSION
from ipalib import api, errors
from ipalib.constants import ANON_USER
from ipalib.install import certmonger
@@ -42,15 +44,17 @@ from ipapython.dogtag import KDC_PROFILE
from ipaserver.install import replication
from ipaserver.install import certs
-from ipaserver.masters import find_providing_servers
+from ipaserver.masters import (
+ find_providing_servers,
+ PAC_TKT_SIGN_SUPPORTED,
+ PKINIT_ENABLED,
+)
from ipaplatform.constants import constants
from ipaplatform.tasks import tasks
from ipaplatform.paths import paths
logger = logging.getLogger(__name__)
-PKINIT_ENABLED = 'pkinitEnabled'
-
MASTER_KEY_TYPE = 'aes256-sha2'
SUPPORTED_ENCTYPES = ('aes256-sha2:special', 'aes128-sha2:special',
'aes256-sha2:normal', 'aes128-sha2:normal',
@@ -169,6 +173,13 @@ class KrbInstance(service.Service):
# Add the host to the ipaserver host group
self._ldap_update(['20-ipaservers_hostgroup.update'])
+ def pac_tkt_sign_support_enable(self):
+ """
+ Advertise PAC ticket signature support in master's KDC entry in LDAP
+ """
+ service.set_service_entry_config(
+ 'KDC', self.fqdn, [PAC_TKT_SIGN_SUPPORTED], self.suffix)
+
def __common_setup(self, realm_name, host_name, domain_name, admin_password):
self.fqdn = host_name
self.realm = realm_name.upper()
@@ -212,6 +223,10 @@ class KrbInstance(service.Service):
self.__common_post_setup()
+ if KRB5_BUILD_VERSION >= parse_version('1.20'):
+ self.step("enable PAC ticket signature support",
+ self.pac_tkt_sign_support_enable)
+
self.start_creation()
self.kpasswd = KpasswdInstance()
@@ -235,6 +250,10 @@ class KrbInstance(service.Service):
self.__common_post_setup()
+ if KRB5_BUILD_VERSION >= parse_version('1.20'):
+ self.step("enable PAC ticket signature support",
+ self.pac_tkt_sign_support_enable)
+
self.start_creation()
self.kpasswd = KpasswdInstance()
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index 5f5a60d10..f8701c8a0 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -18,6 +18,7 @@ import sys
import tempfile
from contextlib import contextmanager
from augeas import Augeas
+from pkg_resources import parse_version
from ipalib import api, x509
from ipalib.constants import RENEWAL_CA_NAME, RA_AGENT_PROFILE, IPA_CA_RECORD
@@ -36,6 +37,7 @@ from ipapython import ipautil, version
from ipapython import ipaldap
from ipapython import directivesetter
from ipapython.dn import DN
+from ipapython.version import KRB5_BUILD_VERSION
from ipaplatform.constants import constants
from ipaplatform.paths import paths
from ipaserver import servroles
@@ -1961,6 +1963,9 @@ def upgrade_configuration():
enable_server_snippet()
setup_kpasswd_server(krb)
+ if KRB5_BUILD_VERSION >= parse_version('1.20'):
+ krb.pac_tkt_sign_support_enable()
+
# Must be executed after certificate_renewal_update
# (see function docstring for details)
http_certificate_ensure_ipa_ca_dnsname(http)
diff --git a/ipaserver/masters.py b/ipaserver/masters.py
index b532f2b72..c9b57b2a5 100644
--- a/ipaserver/masters.py
+++ b/ipaserver/masters.py
@@ -20,6 +20,8 @@ logger = logging.getLogger(__name__)
CONFIGURED_SERVICE = u'configuredService'
ENABLED_SERVICE = u'enabledService'
HIDDEN_SERVICE = u'hiddenService'
+PAC_TKT_SIGN_SUPPORTED = u'pacTktSignSupported'
+PKINIT_ENABLED = u'pkinitEnabled'
# The service name as stored in cn=masters,cn=ipa,cn=etc. The values are:
# 0: systemd service name
--
2.39.2

View 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

View File

@ -1,269 +0,0 @@
From 33242a967011b9cbce74b6b3c39a7247d66eda19 Mon Sep 17 00:00:00 2001
From: Alexander Bokovoy <abokovoy@redhat.com>
Date: Thu, 25 May 2023 09:19:57 +0300
Subject: [PATCH] ipa-kdb: postpone ticket checksum configuration
Postpone ticket checksum configuration after KDB module was initialized.
This, in practice, should now happen when a master key is retrieved.
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Julien Rische <jrische@redhat.com>
(cherry picked from commit fefa0248296413b6ee5ad2543d8feb1b31840aee)
---
daemons/ipa-kdb/ipa_kdb.c | 56 +----------------------
daemons/ipa-kdb/ipa_kdb.h | 8 +++-
daemons/ipa-kdb/ipa_kdb_common.c | 67 +++++++++++++++++++++++++++-
daemons/ipa-kdb/ipa_kdb_principals.c | 14 ++++--
4 files changed, 84 insertions(+), 61 deletions(-)
diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c
index 9a56640ff..a3c3746c2 100644
--- a/daemons/ipa-kdb/ipa_kdb.c
+++ b/daemons/ipa-kdb/ipa_kdb.c
@@ -524,52 +524,6 @@ static krb5_principal ipadb_create_local_tgs(krb5_context kcontext,
return tgtp;
}
-static char *no_attrs[] = {
- LDAP_NO_ATTRS,
-
- NULL
-};
-
-static krb5_error_code
-should_support_pac_tkt_sign(krb5_context kcontext, bool *result)
-{
- struct ipadb_context *ipactx;
- krb5_error_code kerr;
- LDAPMessage *res = NULL;
- char *masters_dn = NULL;
- int count;
-
- char *kdc_filter = "(&(cn=KDC)(objectClass=ipaConfigObject)"
- "(!(ipaConfigString=pacTktSignSupported)))";
-
- ipactx = ipadb_get_context(kcontext);
- if (!ipactx) {
- kerr = KRB5_KDB_DBNOTINITED;
- goto done;
- }
-
- count = asprintf(&masters_dn, "cn=masters,cn=ipa,cn=etc,%s", ipactx->base);
- if (count < 0) {
- kerr = ENOMEM;
- goto done;
- }
-
- kerr = ipadb_simple_search(ipactx, masters_dn, LDAP_SCOPE_SUBTREE,
- kdc_filter, no_attrs, &res);
- if (kerr)
- goto done;
-
- count = ldap_count_entries(ipactx->lcontext, res);
-
- if (result)
- *result = (count == 0);
-
-done:
- free(masters_dn);
- ldap_msgfree(res);
- return kerr;
-}
-
/* INTERFACE */
static krb5_error_code ipadb_init_library(void)
@@ -590,7 +544,6 @@ static krb5_error_code ipadb_init_module(krb5_context kcontext,
krb5_error_code kerr;
int ret;
int i;
- bool pac_tkt_sign_supported;
/* make sure the context is freed to avoid leaking it */
ipactx = ipadb_get_context(kcontext);
@@ -662,6 +615,8 @@ static krb5_error_code ipadb_init_module(krb5_context kcontext,
goto fail;
}
+ ipactx->optional_pac_tkt_chksum = IPADB_TRISTATE_UNDEFINED;
+
ret = ipadb_get_connection(ipactx);
if (ret != 0) {
/* Not a fatal failure, as the LDAP server may be temporarily down. */
@@ -675,13 +630,6 @@ static krb5_error_code ipadb_init_module(krb5_context kcontext,
goto fail;
}
- /* Enforce PAC ticket signature verification if supported by all KDCs */
- kerr = should_support_pac_tkt_sign(kcontext, &pac_tkt_sign_supported);
- if (kerr) {
- ret = kerr;
- goto fail;
- }
- ipactx->optional_pac_tkt_chksum = !pac_tkt_sign_supported;
return 0;
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
index 0f4d3e431..edf3b0dfc 100644
--- a/daemons/ipa-kdb/ipa_kdb.h
+++ b/daemons/ipa-kdb/ipa_kdb.h
@@ -126,6 +126,12 @@ struct ipadb_global_config {
bool disable_preauth_for_spns;
};
+enum ipadb_tristate_option {
+ IPADB_TRISTATE_FALSE = FALSE,
+ IPADB_TRISTATE_TRUE = TRUE,
+ IPADB_TRISTATE_UNDEFINED,
+};
+
#define IPA_CONTEXT_MAGIC 0x0c027ea7
struct ipadb_context {
int magic;
@@ -143,7 +149,7 @@ struct ipadb_context {
krb5_key_salt_tuple *def_encs;
int n_def_encs;
struct ipadb_mspac *mspac;
- bool optional_pac_tkt_chksum;
+ enum ipadb_tristate_option optional_pac_tkt_chksum;
#ifdef HAVE_KRB5_CERTAUTH_PLUGIN
krb5_certauth_moddata certauth_moddata;
#endif
diff --git a/daemons/ipa-kdb/ipa_kdb_common.c b/daemons/ipa-kdb/ipa_kdb_common.c
index 42e0856d0..ae7742a32 100644
--- a/daemons/ipa-kdb/ipa_kdb_common.c
+++ b/daemons/ipa-kdb/ipa_kdb_common.c
@@ -158,12 +158,75 @@ static bool ipadb_need_retry(struct ipadb_context *ipactx, int error)
return false;
}
+static char *no_attrs[] = {
+ LDAP_NO_ATTRS,
+
+ NULL
+};
+
+static int
+should_support_pac_tkt_sign(struct ipadb_context *ipactx, bool *result)
+{
+ int ret;
+ LDAPMessage *res = NULL;
+ char *masters_dn = NULL;
+ int count;
+
+ char *kdc_filter = "(&(cn=KDC)(objectClass=ipaConfigObject)"
+ "(!(ipaConfigString=pacTktSignSupported)))";
+
+ if (!ipactx) {
+ ret = KRB5_KDB_DBNOTINITED;
+ goto done;
+ }
+
+ count = asprintf(&masters_dn, "cn=masters,cn=ipa,cn=etc,%s", ipactx->base);
+ if (count < 0) {
+ ret = ENOMEM;
+ goto done;
+ }
+
+ ret = ipadb_simple_search(ipactx, masters_dn, LDAP_SCOPE_SUBTREE,
+ kdc_filter, no_attrs, &res);
+ if (ret)
+ goto done;
+
+ count = ldap_count_entries(ipactx->lcontext, res);
+
+ if (result)
+ *result = (count == 0);
+
+done:
+ free(masters_dn);
+ ldap_msgfree(res);
+ return ret;
+}
+
static int ipadb_check_connection(struct ipadb_context *ipactx)
{
+ int ret = 0;
+
if (ipactx->lcontext == NULL) {
- return ipadb_get_connection(ipactx);
+ ret = ipadb_get_connection(ipactx);
+ }
+ if ((ret == 0) && (ipactx->optional_pac_tkt_chksum == IPADB_TRISTATE_UNDEFINED)) {
+ bool pac_tkt_sign_supported;
+
+ /* Enforce PAC ticket signature verification if supported by all KDCs
+ * To avoid loops as all search functions call into
+ * ipadb_check_connection(), mark that the init is complete at this
+ * point. Default to not issuing PAC to be safe.
+ */
+ ipactx->optional_pac_tkt_chksum = IPADB_TRISTATE_FALSE;
+ ret = should_support_pac_tkt_sign(ipactx,
+ &pac_tkt_sign_supported);
+ if (ret == 0) {
+ ipactx->optional_pac_tkt_chksum = !pac_tkt_sign_supported;
+ } else {
+ ipactx->optional_pac_tkt_chksum = IPADB_TRISTATE_UNDEFINED;
+ }
}
- return 0;
+ return ret;
}
krb5_error_code ipadb_simple_search(struct ipadb_context *ipactx,
diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c
index e6c3fba21..d35cec2e0 100644
--- a/daemons/ipa-kdb/ipa_kdb_principals.c
+++ b/daemons/ipa-kdb/ipa_kdb_principals.c
@@ -113,7 +113,9 @@ static char *std_principal_obj_classes[] = {
#define DEFAULT_TL_DATA_CONTENT "\x00\x00\x00\x00principal@UNINITIALIZED"
-#define OPT_PAC_TKT_CHKSUM_STR_ATTR_NAME "optional_pac_tkt_chksum"
+#ifndef KRB5_KDB_SK_OPTIONAL_PAC_TKT_CHKSUM
+#define KRB5_KDB_SK_OPTIONAL_PAC_TKT_CHKSUM "optional_pac_tkt_chksum"
+#endif
static int ipadb_ldap_attr_to_tl_data(LDAP *lcontext, LDAPMessage *le,
char *attrname,
@@ -1710,6 +1712,10 @@ krb5_error_code ipadb_get_principal(krb5_context kcontext,
if (kerr)
return kerr;
+ /* We should have been initialized at this point already */
+ if (ipactx->optional_pac_tkt_chksum == IPADB_TRISTATE_UNDEFINED) {
+ return KRB5_KDB_SERVER_INTERNAL_ERR;
+ }
/* PAC ticket signature should be optional for foreign realms, and local
* realm if not supported by all servers
*/
@@ -1719,7 +1725,7 @@ krb5_error_code ipadb_get_principal(krb5_context kcontext,
opt_pac_tkt_chksum_val = "false";
kerr = krb5_dbe_set_string(kcontext, *entry,
- OPT_PAC_TKT_CHKSUM_STR_ATTR_NAME,
+ KRB5_KDB_SK_OPTIONAL_PAC_TKT_CHKSUM,
opt_pac_tkt_chksum_val);
}
@@ -2828,14 +2834,14 @@ remove_virtual_str_attrs(krb5_context kcontext, krb5_db_entry *entry)
krb5_error_code kerr;
kerr = krb5_dbe_get_string(kcontext, entry,
- OPT_PAC_TKT_CHKSUM_STR_ATTR_NAME,
+ KRB5_KDB_SK_OPTIONAL_PAC_TKT_CHKSUM,
&str_attr_val);
if (kerr)
return kerr;
if (str_attr_val)
kerr = krb5_dbe_set_string(kcontext, entry,
- OPT_PAC_TKT_CHKSUM_STR_ATTR_NAME,
+ KRB5_KDB_SK_OPTIONAL_PAC_TKT_CHKSUM,
NULL);
krb5_dbe_free_string(kcontext, str_attr_val);
--
2.39.2

View 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

View File

@ -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

View File

@ -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-----

View 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-----

View File

@ -66,7 +66,7 @@
%if 0%{?rhel}
%global package_name ipa
%global alt_name freeipa
%global krb5_version 1.20.1-9
%global krb5_version 1.20.1-1
%global krb5_kdb_version 9.0
# 0.7.16: https://github.com/drkjam/netaddr/issues/71
%global python_netaddr_version 0.7.19
@ -178,7 +178,7 @@
# RHEL 8.2+, F32+ has 3.58
%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
%if 0%{?fedora} >= 33 || 0%{?rhel} >= 9
@ -210,7 +210,7 @@
# Work-around fact that RPM SPEC parser does not accept
# "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
#%%global rc_version %%nil
%define AT_SIGN @
@ -223,10 +223,10 @@
Name: %{package_name}
Version: %{IPA_VERSION}
Release: 7%{?rc_version:.%rc_version}%{?dist}
Release: 4%{?rc_version:.%rc_version}%{?dist}
Summary: The Identity, Policy and Audit system
License: GPLv3+
License: GPL-3.0-or-later
URL: http://www.freeipa.org/
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
@ -247,30 +247,31 @@ Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch
Patch1002: 1002-Revert-freeipa.spec-depend-on-bind-dnssec-utils.patch
%endif
%if 0%{?rhel} == 9
Patch0001: 0001-updates-fix-memberManager-ACI-to-allow-managers-from.patch
Patch0002: 0002-Spec-file-ipa-client-depends-on-krb5-pkinit-openssl.patch
Patch0003: 0003-server-install-remove-error-log-about-missing-bkup-f.patch
Patch0004: 0004-ipa-tests-Add-LANG-before-kinit-command-to-fix-issue.patch
Patch0005: 0005-trust-add-handle-missing-msSFU30MaxGidNumber.patch
Patch0006: 0006-doc-Design-for-certificate-pruning.patch
Patch0007: 0007-ipa-acme-manage-add-certificate-request-pruning-mana.patch
Patch0008: 0008-doc-add-the-run-command-for-manual-job-execution.patch
Patch0009: 0009-tests-add-wrapper-around-ACME-RSNv3-test.patch
Patch0010: 0010-automember-rebuild-add-a-notice-about-high-CPU-usage.patch
Patch0011: 0011-Fix-setting-values-of-0-in-ACME-pruning.patch
Patch0012: 0012-Wipe-the-ipa-ca-DNS-record-when-updating-system-reco.patch
Patch0013: 0013-ipa-kdb-PAC-consistency-checker-needs-to-handle-chil.patch
Patch0014: 0014-Add-test-for-SSH-with-GSSAPI-auth.patch
Patch0015: 0015-webui-tests-fix-assertion-in-test_subid.py.patch
Patch0016: 0016-ipatests-mark-test_smb-as-xfail.patch
Patch0017: 0017-Tests-force-key-type-in-ACME-tests.patch
Patch0018: 0018-tests-Add-ipa_ca_name-checking-to-DNS-system-records.patch
Patch0019: 0019-tests-Add-new-ipa-ca-error-messages-to-IPADNSSystemR.patch
Patch0020: 0020-ipatests-tests-for-certificate-pruning.patch
Patch0021: 0021-ipatests-ensure-that-ipa-automember-rebuild-prints-a.patch
Patch0022: 0022-ipatests-fix-tests-in-TestACMEPrune.patch
Patch0023: 0023-Tolerate-absence-of-PAC-ticket-signature-depending-o.patch
Patch0024: 0024-ipa-kdb-postpone-ticket-checksum-configuration.patch
Patch0001: 0001-webuitests-close-notification-which-hides-Add-button.patch
Patch0002: 0002-ipatests-Check-that-SSSD_PUBCONF_KRB5_INCLUDE_D_DIR-.patch
Patch0003: 0003-Revert-Use-the-OpenSSL-certificate-parser-in-cert-fi.patch
Patch0004: 0004-Revert-cert_find-fix-call-with-all.patch
Patch0005: 0005-Use-the-python-cryptography-parser-directly-in-cert-.patch
Patch0006: 0006-Upgrade-add-PKI-drop-in-file-if-missing.patch
Patch0007: 0007-Integration-test-add-a-test-for-upgrade-and-PKI-drop.patch
Patch0008: 0008-Uninstaller-uninstall-PKI-before-shutting-down-servi.patch
Patch0009: 0009-Detection-of-PKI-subsystem.patch
Patch0010: 0010-Upgrade-fix-replica-agreement.patch
Patch0011: 0011-Integration-tests-add-a-test-to-ipa-server-upgrade.patch
Patch0012: 0012-tests-fix-backup-restore-scenario-with-replica.patch
Patch0013: 0013-OTP-fix-data-type-to-avoid-endianness-issue.patch
Patch0014: 0014-ipatests-enable-firewall-rule-for-http-service-on-ac.patch
Patch0015: 0015-User-plugin-improve-error-related-to-non-existing-id.patch
Patch0016: 0016-xmlrpc-tests-add-a-test-for-user-plugin-with-non-exi.patch
Patch0017: 0017-Fix-memory-leak-in-the-OTP-last-token-plugin.patch
Patch0018: 0018-Prevent-the-admin-user-from-being-deleted.patch
Patch0019: 0019-ipa-kdb-fix-error-handling-of-is_master_host.patch
Patch0020: 0020-ipatests-update-expected-webui-msg-for-admin-deletio.patch
Patch0021: 0021-ipatests-remove-fixture-call-and-wait-to-get-things-.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
%endif
%endif
@ -321,7 +322,12 @@ BuildRequires: libpwquality-devel
BuildRequires: libsss_idmap-devel
BuildRequires: libsss_certmap-devel
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)
%else
BuildRequires: nodejs(abi) < 111
%endif
# use old dependency on RHEL 8 for now
%if 0%{?fedora} >= 31 || 0%{?rhel} >= 9
BuildRequires: python3-rjsmin
@ -502,7 +508,7 @@ Requires: policycoreutils >= 2.1.12-5
Requires: tar
Requires(pre): certmonger >= %{certmonger_version}
Requires(pre): 389-ds-base >= %{ds_version}
Requires: fontawesome-fonts
Requires: font(fontawesome)
Requires: open-sans-fonts
%if 0%{?fedora} >= 32 || 0%{?rhel} >= 9
# https://pagure.io/freeipa/issue/8632
@ -716,6 +722,7 @@ Requires: jansson
%endif
Requires: sssd-ipa >= %{sssd_version}
Requires: sssd-idp >= %{sssd_version}
Requires: sssd-krb5 >= %{sssd_version}
Requires: certmonger >= %{certmonger_version}
Requires: nss-tools >= %{nss_version}
Requires: bind-utils
@ -1261,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}')
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
echo "includedir /var/lib/sss/pubconf/krb5.include.d/" > /etc/krb5.conf.ipanew
cat /etc/krb5.conf >> /etc/krb5.conf.ipanew
mv -Z /etc/krb5.conf.ipanew /etc/krb5.conf
if grep -E -q '/var/lib/sss/pubconf/krb5.include.d/' /etc/krb5.conf 2>/dev/null ; then
sed -i '\;includedir /var/lib/sss/pubconf/krb5.include.d;d' /etc/krb5.conf
fi
fi
@ -1758,8 +1763,34 @@ fi
%endif
%changelog
* Thu Jun 01 2023 Julien Rische <jrische@redhat.com> - 4.10.1-7
- Resolves: rhbz#2211389 Handle PAC signatures based on domain and server capabilities
* 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
- Resolves: rhbz#2169632 Backport latest test fixes in python3-ipatests