Compare commits
No commits in common. "c8-stream-DL1" and "c9-beta" have entirely different histories.
c8-stream-
...
c9-beta
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1 @@
|
||||
SOURCES/freeipa-4.9.13.tar.gz
|
||||
SOURCES/freeipa-4.12.2.tar.gz
|
||||
|
@ -1 +1 @@
|
||||
da1bb0220894d8dc06afb98dcf087fea38076a79 SOURCES/freeipa-4.9.13.tar.gz
|
||||
e06782e6f1d33fdbdc27011d10737c8d2fb815a8 SOURCES/freeipa-4.12.2.tar.gz
|
||||
|
@ -1,73 +0,0 @@
|
||||
From 06b4c61b4484efe2093501caf21b03f1fc14093b Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Thu, 19 Oct 2023 12:47:03 +0200
|
||||
Subject: [PATCH] group-add-member fails with an external member
|
||||
|
||||
The command ipa group-add-member --external aduser@addomain.test
|
||||
fails with an internal error when used with samba 4.19.
|
||||
|
||||
The command internally calls samba.security.dom_sid(sid) which
|
||||
used to raise a TypeError but now raises a ValueError
|
||||
(commit 9abdd67 on https://github.com/samba-team/samba).
|
||||
|
||||
IPA source code needs to handle properly both exception types.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9466
|
||||
|
||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipaserver/dcerpc.py | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
|
||||
index c1db2f9a499..ee0a229d1f0 100644
|
||||
--- a/ipaserver/dcerpc.py
|
||||
+++ b/ipaserver/dcerpc.py
|
||||
@@ -303,7 +303,7 @@ def get_domain_by_sid(self, sid, exact_match=False):
|
||||
# Parse sid string to see if it is really in a SID format
|
||||
try:
|
||||
test_sid = security.dom_sid(sid)
|
||||
- except TypeError:
|
||||
+ except (TypeError, ValueError):
|
||||
raise errors.ValidationError(name='sid',
|
||||
error=_('SID is not valid'))
|
||||
|
||||
From aa3397378acf1a03fc8bbe34b9fae33e84588b34 Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Fri, 20 Oct 2023 10:20:57 +0200
|
||||
Subject: [PATCH] Handle samba changes in samba.security.dom_sid()
|
||||
|
||||
samba.security.dom_sid() in 4.19 now raises ValueError instead of
|
||||
TypeError. Fix the expected exception.
|
||||
|
||||
Related: https://pagure.io/freeipa/issue/9466
|
||||
|
||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
---
|
||||
ipaserver/dcerpc.py | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
|
||||
index ee0a229d1f0..3e4c71d9976 100644
|
||||
--- a/ipaserver/dcerpc.py
|
||||
+++ b/ipaserver/dcerpc.py
|
||||
@@ -97,7 +97,7 @@
|
||||
def is_sid_valid(sid):
|
||||
try:
|
||||
security.dom_sid(sid)
|
||||
- except TypeError:
|
||||
+ except (TypeError, ValueError):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
@@ -457,7 +457,7 @@ def get_trusted_domain_object_sid(self, object_name,
|
||||
try:
|
||||
test_sid = security.dom_sid(sid)
|
||||
return unicode(test_sid)
|
||||
- except TypeError:
|
||||
+ except (TypeError, ValueError):
|
||||
raise errors.ValidationError(name=_('trusted domain object'),
|
||||
error=_('Trusted domain did not '
|
||||
'return a valid SID for '
|
238
SOURCES/0001-Revert-Replace-netifaces-with-ifaddr.patch
Normal file
238
SOURCES/0001-Revert-Replace-netifaces-with-ifaddr.patch
Normal file
@ -0,0 +1,238 @@
|
||||
From dfeb01d5e4e8934bae8f495bbbd5b6570f3dc862 Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Tue, 4 Jun 2024 13:56:56 +0200
|
||||
Subject: [PATCH] Revert "Replace netifaces with ifaddr"
|
||||
|
||||
This reverts commit 6c6b9354b5f970983655ca5423c726763d9015fa.
|
||||
---
|
||||
doc/requirements.txt | 1 -
|
||||
freeipa.spec.in | 4 +--
|
||||
ipaclient/install/client.py | 43 ++++++++++++++-----------------
|
||||
ipapython/ipautil.py | 51 ++++++++++++++++++++-----------------
|
||||
ipapython/setup.py | 2 +-
|
||||
ipasetup.py.in | 2 +-
|
||||
pylintrc | 1 +
|
||||
7 files changed, 52 insertions(+), 52 deletions(-)
|
||||
|
||||
diff --git a/doc/requirements.txt b/doc/requirements.txt
|
||||
index 8d91b893fbcb5de784f5abdf802b976c6b2ae277..cdaa42658c73e495379d87b7c50195fbd79533ee 100644
|
||||
--- a/doc/requirements.txt
|
||||
+++ b/doc/requirements.txt
|
||||
@@ -11,7 +11,6 @@ m2r2
|
||||
## ipa dependencies
|
||||
dnspython
|
||||
jwcrypto
|
||||
-ifaddr
|
||||
netaddr
|
||||
qrcode
|
||||
six
|
||||
diff --git a/freeipa.spec.in b/freeipa.spec.in
|
||||
index 6803de752bc122bf6e1eafd610d399cde994cad5..a532fe85c34a523519187b6fd1297c198d9f4a4e 100755
|
||||
--- a/freeipa.spec.in
|
||||
+++ b/freeipa.spec.in
|
||||
@@ -403,7 +403,7 @@ BuildRequires: python3-libipa_hbac
|
||||
BuildRequires: python3-libsss_nss_idmap
|
||||
BuildRequires: python3-lxml
|
||||
BuildRequires: python3-netaddr >= %{python_netaddr_version}
|
||||
-BuildRequires: python3-ifaddr
|
||||
+BuildRequires: python3-netifaces
|
||||
BuildRequires: python3-pki >= %{pki_version}
|
||||
BuildRequires: python3-polib
|
||||
BuildRequires: python3-pyasn1
|
||||
@@ -885,7 +885,7 @@ Requires: python3-gssapi >= 1.2.0
|
||||
Requires: python3-jwcrypto >= 0.4.2
|
||||
Requires: python3-libipa_hbac
|
||||
Requires: python3-netaddr >= %{python_netaddr_version}
|
||||
-Requires: python3-ifaddr
|
||||
+Requires: python3-netifaces >= 0.10.4
|
||||
Requires: python3-pyasn1 >= 0.3.2-2
|
||||
Requires: python3-pyasn1-modules >= 0.3.2-2
|
||||
Requires: python3-pyusb
|
||||
diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py
|
||||
index 29aff5f413e7f27136e236382031171f068284c5..263dc8e302cccd76412c294e0740af9744a2c62d 100644
|
||||
--- a/ipaclient/install/client.py
|
||||
+++ b/ipaclient/install/client.py
|
||||
@@ -18,7 +18,7 @@ import logging
|
||||
import dns
|
||||
import getpass
|
||||
import gssapi
|
||||
-import ifaddr
|
||||
+import netifaces
|
||||
import os
|
||||
import re
|
||||
import SSSDConfig
|
||||
@@ -1374,36 +1374,31 @@ def unconfigure_nisdomain(statestore):
|
||||
|
||||
|
||||
def get_iface_from_ip(ip_addr):
|
||||
- for adapter in ifaddr.get_adapters():
|
||||
- for ips in adapter.ips:
|
||||
- # IPv6 is reported as a tuple, IPv4 is reported as str
|
||||
- if ip_addr in (ips.ip[0], ips.ip):
|
||||
- return adapter.name
|
||||
+ for interface in netifaces.interfaces():
|
||||
+ if_addrs = netifaces.ifaddresses(interface)
|
||||
+ for family in [netifaces.AF_INET, netifaces.AF_INET6]:
|
||||
+ for ip in if_addrs.get(family, []):
|
||||
+ if ip['addr'] == ip_addr:
|
||||
+ return interface
|
||||
raise RuntimeError("IP %s not assigned to any interface." % ip_addr)
|
||||
|
||||
|
||||
-def __get_ifaddr_adapters(iface=None):
|
||||
+def get_local_ipaddresses(iface=None):
|
||||
if iface:
|
||||
- interfaces = set(iface if isinstance(iface, (list, tuple)) else [iface])
|
||||
+ interfaces = [iface]
|
||||
else:
|
||||
- interfaces = set(adapter.name for adapter in ifaddr.get_adapters())
|
||||
- return [
|
||||
- adapter
|
||||
- for adapter in ifaddr.get_adapters()
|
||||
- if adapter.name in interfaces or adapter.nice_name in interfaces
|
||||
- ]
|
||||
+ interfaces = netifaces.interfaces()
|
||||
|
||||
-
|
||||
-def get_local_ipaddresses(iface=None):
|
||||
ips = []
|
||||
- for adapter in __get_ifaddr_adapters(iface):
|
||||
- for ifip in adapter.ips:
|
||||
- try:
|
||||
- ip_addr = ifip.ip[0] if isinstance(ifip.ip, tuple) else ifip.ip
|
||||
- ips.append(ipautil.CheckedIPAddress(ip_addr))
|
||||
- logger.debug('IP check successful: %s', ip_addr)
|
||||
- except ValueError as e:
|
||||
- logger.debug('IP check failed: %s', e)
|
||||
+ for interface in interfaces:
|
||||
+ if_addrs = netifaces.ifaddresses(interface)
|
||||
+ for family in [netifaces.AF_INET, netifaces.AF_INET6]:
|
||||
+ for ip in if_addrs.get(family, []):
|
||||
+ try:
|
||||
+ ips.append(ipautil.CheckedIPAddress(ip['addr']))
|
||||
+ logger.debug('IP check successful: %s', ip['addr'])
|
||||
+ except ValueError as e:
|
||||
+ logger.debug('IP check failed: %s', e)
|
||||
return ips
|
||||
|
||||
|
||||
diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
|
||||
index b02d58839ed74215d7253fc23be94846d689f91e..6802dde574d179b2d4bf868a2c38546cc01fc46b 100644
|
||||
--- a/ipapython/ipautil.py
|
||||
+++ b/ipapython/ipautil.py
|
||||
@@ -48,9 +48,9 @@ import six
|
||||
from six.moves import input
|
||||
|
||||
try:
|
||||
- import ifaddr
|
||||
+ import netifaces
|
||||
except ImportError:
|
||||
- ifaddr = None
|
||||
+ netifaces = None
|
||||
|
||||
from ipapython.dn import DN
|
||||
from ipaplatform.paths import paths
|
||||
@@ -203,37 +203,42 @@ class CheckedIPAddress(UnsafeIPAddress):
|
||||
:return: InterfaceDetails named tuple or None if no interface has
|
||||
this address
|
||||
"""
|
||||
- if ifaddr is None:
|
||||
- raise ImportError("ifaddr")
|
||||
+ if netifaces is None:
|
||||
+ raise ImportError("netifaces")
|
||||
logger.debug("Searching for an interface of IP address: %s", self)
|
||||
-
|
||||
if self.version == 4:
|
||||
- family_ips = (
|
||||
- (ip.ip, ip.network_prefix, ip.nice_name)
|
||||
- for ips in [a.ips for a in ifaddr.get_adapters()]
|
||||
- for ip in ips if not isinstance(ip.ip, tuple)
|
||||
- )
|
||||
+ family = netifaces.AF_INET
|
||||
elif self.version == 6:
|
||||
- family_ips = (
|
||||
- (ip.ip[0], ip.network_prefix, ip.nice_name)
|
||||
- for ips in [a.ips for a in ifaddr.get_adapters()]
|
||||
- for ip in ips if isinstance(ip.ip, tuple)
|
||||
- )
|
||||
+ family = netifaces.AF_INET6
|
||||
else:
|
||||
raise ValueError(
|
||||
"Unsupported address family ({})".format(self.version)
|
||||
)
|
||||
|
||||
- for ip, prefix, ifname in family_ips:
|
||||
- ifaddrmask = "{ip}/{prefix}".format(ip=ip, prefix=prefix)
|
||||
- logger.debug(
|
||||
- "Testing local IP address: %s (interface: %s)",
|
||||
- ifaddrmask, ifname)
|
||||
- ifnet = netaddr.IPNetwork(ifaddrmask)
|
||||
+ for interface in netifaces.interfaces():
|
||||
+ for ifdata in netifaces.ifaddresses(interface).get(family, []):
|
||||
+
|
||||
+ # link-local addresses contain '%suffix' that causes parse
|
||||
+ # errors in IPNetwork
|
||||
+ ifaddr = ifdata['addr'].split(u'%', 1)[0]
|
||||
+
|
||||
+ # newer versions of netifaces provide IPv6 netmask in format
|
||||
+ # 'ffff:ffff:ffff:ffff::/64'. We have to split and use prefix
|
||||
+ # or the netmask with older versions
|
||||
+ ifmask = ifdata['netmask'].split(u'/')[-1]
|
||||
+
|
||||
+ ifaddrmask = '{addr}/{netmask}'.format(
|
||||
+ addr=ifaddr,
|
||||
+ netmask=ifmask
|
||||
+ )
|
||||
+ logger.debug(
|
||||
+ "Testing local IP address: %s (interface: %s)",
|
||||
+ ifaddrmask, interface)
|
||||
|
||||
- if ifnet.ip == self:
|
||||
- return InterfaceDetails(ifname, ifnet)
|
||||
+ ifnet = netaddr.IPNetwork(ifaddrmask)
|
||||
|
||||
+ if ifnet.ip == self:
|
||||
+ return InterfaceDetails(interface, ifnet)
|
||||
return None
|
||||
|
||||
def set_ip_net(self, ifnet):
|
||||
diff --git a/ipapython/setup.py b/ipapython/setup.py
|
||||
index b7b25c8b480f0dc80ae20c4027554b27fe6d87b3..ea55f5c729e8ba65a4436ebf3eb4898870558648 100644
|
||||
--- a/ipapython/setup.py
|
||||
+++ b/ipapython/setup.py
|
||||
@@ -48,6 +48,6 @@ if __name__ == '__main__':
|
||||
extras_require={
|
||||
"ldap": ["python-ldap"], # ipapython.ipaldap
|
||||
# CheckedIPAddress.get_matching_interface
|
||||
- "ifaddr": ["ifaddr"],
|
||||
+ "netifaces": ["netifaces"],
|
||||
},
|
||||
)
|
||||
diff --git a/ipasetup.py.in b/ipasetup.py.in
|
||||
index 56a1f3b066c70385949c86d0d35ce393331ad1c5..25eac3b214b4e6443fe29dd3d656c2fdbe84343a 100644
|
||||
--- a/ipasetup.py.in
|
||||
+++ b/ipasetup.py.in
|
||||
@@ -75,7 +75,7 @@ PACKAGE_VERSION = {
|
||||
'ipaserver': 'ipaserver == {}'.format(VERSION),
|
||||
'jwcrypto': 'jwcrypto >= 0.4.2',
|
||||
'kdcproxy': 'kdcproxy >= 0.3',
|
||||
- 'ifaddr': 'ifaddr >= 0.1.7',
|
||||
+ 'netifaces': 'netifaces >= 0.10.4',
|
||||
'python-ldap': 'python-ldap >= 3.0.0',
|
||||
'python-yubico': 'python-yubico >= 1.2.3',
|
||||
'qrcode': 'qrcode >= 5.0',
|
||||
diff --git a/pylintrc b/pylintrc
|
||||
index 50278cc76031af68959a138f6ea185c4288c7155..22053a9b55e9dc8e71c1835a63c9393e8ad6803d 100644
|
||||
--- a/pylintrc
|
||||
+++ b/pylintrc
|
||||
@@ -13,6 +13,7 @@ extension-pkg-allow-list=
|
||||
_ldap,
|
||||
cryptography,
|
||||
gssapi,
|
||||
+ netifaces,
|
||||
lxml.etree,
|
||||
pysss_murmur,
|
||||
|
||||
--
|
||||
2.45.1
|
||||
|
@ -1,121 +0,0 @@
|
||||
From ae006b436cfb4ccee5972cf1db0a309fcd80e669 Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Fri, 6 Oct 2023 20:16:29 +0000
|
||||
Subject: [PATCH] Check the HTTP Referer header on all requests
|
||||
|
||||
The referer was only checked in WSGIExecutioner classes:
|
||||
|
||||
- jsonserver
|
||||
- KerberosWSGIExecutioner
|
||||
- xmlserver
|
||||
- jsonserver_kerb
|
||||
|
||||
This left /i18n_messages, /session/login_kerberos,
|
||||
/session/login_x509, /session/login_password,
|
||||
/session/change_password and /session/sync_token unprotected
|
||||
against CSRF attacks.
|
||||
|
||||
CVE-2023-5455
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipaserver/rpcserver.py | 34 +++++++++++++++++++++++++++++++---
|
||||
1 file changed, 31 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py
|
||||
index 4e8a08b66..3555014ca 100644
|
||||
--- a/ipaserver/rpcserver.py
|
||||
+++ b/ipaserver/rpcserver.py
|
||||
@@ -156,6 +156,19 @@ _success_template = """<html>
|
||||
</html>"""
|
||||
|
||||
class HTTP_Status(plugable.Plugin):
|
||||
+ def check_referer(self, environ):
|
||||
+ if "HTTP_REFERER" not in environ:
|
||||
+ logger.error("Rejecting request with missing Referer")
|
||||
+ return False
|
||||
+ if (not environ["HTTP_REFERER"].startswith(
|
||||
+ "https://%s/ipa" % self.api.env.host)
|
||||
+ and not self.env.in_tree):
|
||||
+ logger.error("Rejecting request with bad Referer %s",
|
||||
+ environ["HTTP_REFERER"])
|
||||
+ return False
|
||||
+ logger.debug("Valid Referer %s", environ["HTTP_REFERER"])
|
||||
+ return True
|
||||
+
|
||||
def not_found(self, environ, start_response, url, message):
|
||||
"""
|
||||
Return a 404 Not Found error.
|
||||
@@ -331,9 +344,6 @@ class wsgi_dispatch(Executioner, HTTP_Status):
|
||||
self.__apps[key] = app
|
||||
|
||||
|
||||
-
|
||||
-
|
||||
-
|
||||
class WSGIExecutioner(Executioner):
|
||||
"""
|
||||
Base class for execution backends with a WSGI application interface.
|
||||
@@ -897,6 +907,9 @@ class jsonserver_session(jsonserver, KerberosSession):
|
||||
|
||||
logger.debug('WSGI jsonserver_session.__call__:')
|
||||
|
||||
+ if not self.check_referer(environ):
|
||||
+ return self.bad_request(environ, start_response, 'denied')
|
||||
+
|
||||
# Redirect to login if no Kerberos credentials
|
||||
ccache_name = self.get_environ_creds(environ)
|
||||
if ccache_name is None:
|
||||
@@ -949,6 +962,9 @@ class KerberosLogin(Backend, KerberosSession):
|
||||
def __call__(self, environ, start_response):
|
||||
logger.debug('WSGI KerberosLogin.__call__:')
|
||||
|
||||
+ if not self.check_referer(environ):
|
||||
+ return self.bad_request(environ, start_response, 'denied')
|
||||
+
|
||||
# Redirect to login if no Kerberos credentials
|
||||
user_ccache_name = self.get_environ_creds(environ)
|
||||
if user_ccache_name is None:
|
||||
@@ -967,6 +983,9 @@ class login_x509(KerberosLogin):
|
||||
def __call__(self, environ, start_response):
|
||||
logger.debug('WSGI login_x509.__call__:')
|
||||
|
||||
+ if not self.check_referer(environ):
|
||||
+ return self.bad_request(environ, start_response, 'denied')
|
||||
+
|
||||
if 'KRB5CCNAME' not in environ:
|
||||
return self.unauthorized(
|
||||
environ, start_response, 'KRB5CCNAME not set',
|
||||
@@ -1015,6 +1034,9 @@ class login_password(Backend, KerberosSession):
|
||||
|
||||
logger.debug('WSGI login_password.__call__:')
|
||||
|
||||
+ if not self.check_referer(environ):
|
||||
+ return self.bad_request(environ, start_response, 'denied')
|
||||
+
|
||||
# Get the user and password parameters from the request
|
||||
content_type = environ.get('CONTENT_TYPE', '').lower()
|
||||
if not content_type.startswith('application/x-www-form-urlencoded'):
|
||||
@@ -1147,6 +1169,9 @@ class change_password(Backend, HTTP_Status):
|
||||
def __call__(self, environ, start_response):
|
||||
logger.info('WSGI change_password.__call__:')
|
||||
|
||||
+ if not self.check_referer(environ):
|
||||
+ return self.bad_request(environ, start_response, 'denied')
|
||||
+
|
||||
# Get the user and password parameters from the request
|
||||
content_type = environ.get('CONTENT_TYPE', '').lower()
|
||||
if not content_type.startswith('application/x-www-form-urlencoded'):
|
||||
@@ -1364,6 +1389,9 @@ class xmlserver_session(xmlserver, KerberosSession):
|
||||
|
||||
logger.debug('WSGI xmlserver_session.__call__:')
|
||||
|
||||
+ if not self.check_referer(environ):
|
||||
+ return self.bad_request(environ, start_response, 'denied')
|
||||
+
|
||||
ccache_name = environ.get('KRB5CCNAME')
|
||||
|
||||
# Redirect to /ipa/xml if no Kerberos credentials
|
||||
--
|
||||
2.41.0
|
||||
|
@ -0,0 +1,91 @@
|
||||
From bf6653418aa772b47e53f1af092382df5810661c Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Wed, 5 Jun 2024 15:03:54 +0200
|
||||
Subject: [PATCH] Revert "custodia: do not use deprecated jwcrypto wrappers"
|
||||
|
||||
This reverts commit 536812080502baa51818d9a33ea6533675800b30.
|
||||
---
|
||||
install/tools/ipa-custodia-check.in | 4 ++--
|
||||
ipaserver/custodia/message/kem.py | 14 +++++++-------
|
||||
2 files changed, 9 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/install/tools/ipa-custodia-check.in b/install/tools/ipa-custodia-check.in
|
||||
index f3bbf8e7f0eca6e35080fb6770c9d4b1887384ea..4f526b433f872fa7d94e827df0bb206b78a9b58d 100644
|
||||
--- a/install/tools/ipa-custodia-check.in
|
||||
+++ b/install/tools/ipa-custodia-check.in
|
||||
@@ -192,10 +192,10 @@ class IPACustodiaTester:
|
||||
usage, IPA_CUSTODIA_KEYFILE
|
||||
))
|
||||
|
||||
- if pkey.get('kid') != self.host_spn:
|
||||
+ if pkey.key_id != self.host_spn:
|
||||
raise self.error( # pylint: disable=raising-bad-type, #4772
|
||||
"KID '{}' != host service principal name '{}' "
|
||||
- "(usage: {})".format(pkey.get('kid'), self.host_spn, usage),
|
||||
+ "(usage: {})".format(pkey.key_id, self.host_spn, usage),
|
||||
fatal=True
|
||||
)
|
||||
else:
|
||||
diff --git a/ipaserver/custodia/message/kem.py b/ipaserver/custodia/message/kem.py
|
||||
index c2996bc921aeac0241111d95194977f9aa630cae..fbbc3fe46f60d25fe1754af70b18bb769c127fa2 100644
|
||||
--- a/ipaserver/custodia/message/kem.py
|
||||
+++ b/ipaserver/custodia/message/kem.py
|
||||
@@ -85,7 +85,7 @@ class KEMKeysStore(SimplePathAuthz):
|
||||
if self._alg is None:
|
||||
alg = self.config.get('signing_algorithm', None)
|
||||
if alg is None:
|
||||
- ktype = self.server_keys[KEY_USAGE_SIG]['kty']
|
||||
+ ktype = self.server_keys[KEY_USAGE_SIG].key_type
|
||||
if ktype == 'RSA':
|
||||
alg = 'RS256'
|
||||
elif ktype == 'EC':
|
||||
@@ -125,9 +125,9 @@ class KEMHandler(MessageHandler):
|
||||
if 'kid' not in header:
|
||||
raise InvalidMessage("Missing key identifier")
|
||||
|
||||
- key = self.kkstore.find_key(header.get('kid'), usage)
|
||||
+ key = self.kkstore.find_key(header['kid'], usage)
|
||||
if key is None:
|
||||
- raise UnknownPublicKey('Key found [kid:%s]' % header.get('kid'))
|
||||
+ raise UnknownPublicKey('Key found [kid:%s]' % header['kid'])
|
||||
return json_decode(key)
|
||||
|
||||
def parse(self, msg, name):
|
||||
@@ -179,14 +179,14 @@ class KEMHandler(MessageHandler):
|
||||
self.msg_type = 'kem'
|
||||
|
||||
return {'type': self.msg_type,
|
||||
- 'value': {'kid': self.client_keys[KEY_USAGE_ENC].get('kid'),
|
||||
+ 'value': {'kid': self.client_keys[KEY_USAGE_ENC].key_id,
|
||||
'claims': claims}}
|
||||
|
||||
def reply(self, output):
|
||||
if self.client_keys is None:
|
||||
raise UnknownPublicKey("Peer key not defined")
|
||||
|
||||
- ktype = self.client_keys[KEY_USAGE_ENC]['kty']
|
||||
+ ktype = self.client_keys[KEY_USAGE_ENC].key_type
|
||||
if ktype == 'RSA':
|
||||
enc = ('RSA-OAEP', 'A256CBC-HS512')
|
||||
else:
|
||||
@@ -224,7 +224,7 @@ class KEMClient:
|
||||
|
||||
|
||||
def make_sig_kem(name, value, key, alg):
|
||||
- header = {'kid': key.get('kid'), 'alg': alg}
|
||||
+ header = {'kid': key.key_id, 'alg': alg}
|
||||
claims = {'sub': name, 'exp': int(time.time() + (5 * 60))}
|
||||
if value is not None:
|
||||
claims['value'] = value
|
||||
@@ -235,7 +235,7 @@ def make_sig_kem(name, value, key, alg):
|
||||
|
||||
def make_enc_kem(name, value, sig_key, alg, enc_key, enc):
|
||||
plaintext = make_sig_kem(name, value, sig_key, alg)
|
||||
- eprot = {'kid': enc_key.get('kid'), 'alg': enc[0], 'enc': enc[1]}
|
||||
+ eprot = {'kid': enc_key.key_id, 'alg': enc[0], 'enc': enc[1]}
|
||||
jwe = JWE(plaintext, json_encode(eprot))
|
||||
jwe.add_recipient(enc_key)
|
||||
return jwe.serialize(compact=True)
|
||||
--
|
||||
2.45.1
|
||||
|
@ -1,359 +0,0 @@
|
||||
From f1f8b16def3e809f5773bb8aa40aefb21699347b Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Thu, 12 Oct 2023 20:34:01 +0000
|
||||
Subject: [PATCH] Integration tests for verifying Referer header in the UI
|
||||
|
||||
Validate that the change_password and login_password endpoints
|
||||
verify the HTTP Referer header. There is some overlap in the
|
||||
tests: belt and suspenders.
|
||||
|
||||
All endpoints except session/login_x509 are covered, sometimes
|
||||
having to rely on expected bad results (see the i18n endpoint).
|
||||
|
||||
session/login_x509 is not tested yet as it requires significant
|
||||
additional setup in order to associate a user certificate with
|
||||
a user entry, etc.
|
||||
|
||||
This can be manually verified by modifying /etc/httpd/conf.d/ipa.conf
|
||||
and adding:
|
||||
|
||||
Satisfy Any
|
||||
Require all granted
|
||||
|
||||
Then comment out Auth and SSLVerify, etc. and restart httpd.
|
||||
|
||||
With a valid Referer will fail with a 401 and log that there is no
|
||||
KRB5CCNAME. This comes after the referer check.
|
||||
|
||||
With an invalid Referer it will fail with a 400 Bad Request as
|
||||
expected.
|
||||
|
||||
CVE-2023-5455
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipatests/test_ipaserver/httptest.py | 7 +-
|
||||
ipatests/test_ipaserver/test_changepw.py | 12 +-
|
||||
.../test_ipaserver/test_login_password.py | 88 ++++++++++++
|
||||
ipatests/test_ipaserver/test_referer.py | 136 ++++++++++++++++++
|
||||
ipatests/util.py | 4 +-
|
||||
5 files changed, 242 insertions(+), 5 deletions(-)
|
||||
create mode 100644 ipatests/test_ipaserver/test_login_password.py
|
||||
create mode 100644 ipatests/test_ipaserver/test_referer.py
|
||||
|
||||
diff --git a/ipatests/test_ipaserver/httptest.py b/ipatests/test_ipaserver/httptest.py
|
||||
index 6cd034a71..8924798fc 100644
|
||||
--- a/ipatests/test_ipaserver/httptest.py
|
||||
+++ b/ipatests/test_ipaserver/httptest.py
|
||||
@@ -36,7 +36,7 @@ class Unauthorized_HTTP_test:
|
||||
content_type = 'application/x-www-form-urlencoded'
|
||||
accept_language = 'en-us'
|
||||
|
||||
- def send_request(self, method='POST', params=None):
|
||||
+ def send_request(self, method='POST', params=None, host=None):
|
||||
"""
|
||||
Send a request to HTTP server
|
||||
|
||||
@@ -45,7 +45,10 @@ class Unauthorized_HTTP_test:
|
||||
if params is not None:
|
||||
if self.content_type == 'application/x-www-form-urlencoded':
|
||||
params = urllib.parse.urlencode(params, True)
|
||||
- url = 'https://' + self.host + self.app_uri
|
||||
+ if host:
|
||||
+ url = 'https://' + host + self.app_uri
|
||||
+ else:
|
||||
+ url = 'https://' + self.host + self.app_uri
|
||||
|
||||
headers = {'Content-Type': self.content_type,
|
||||
'Accept-Language': self.accept_language,
|
||||
diff --git a/ipatests/test_ipaserver/test_changepw.py b/ipatests/test_ipaserver/test_changepw.py
|
||||
index c3a47ab26..df38ddb3d 100644
|
||||
--- a/ipatests/test_ipaserver/test_changepw.py
|
||||
+++ b/ipatests/test_ipaserver/test_changepw.py
|
||||
@@ -53,10 +53,11 @@ class test_changepw(XMLRPC_test, Unauthorized_HTTP_test):
|
||||
|
||||
request.addfinalizer(fin)
|
||||
|
||||
- def _changepw(self, user, old_password, new_password):
|
||||
+ def _changepw(self, user, old_password, new_password, host=None):
|
||||
return self.send_request(params={'user': str(user),
|
||||
'old_password' : str(old_password),
|
||||
'new_password' : str(new_password)},
|
||||
+ host=host
|
||||
)
|
||||
|
||||
def _checkpw(self, user, password):
|
||||
@@ -89,6 +90,15 @@ class test_changepw(XMLRPC_test, Unauthorized_HTTP_test):
|
||||
# make sure that password is NOT changed
|
||||
self._checkpw(testuser, old_password)
|
||||
|
||||
+ def test_invalid_referer(self):
|
||||
+ response = self._changepw(testuser, old_password, new_password,
|
||||
+ 'attacker.test')
|
||||
+
|
||||
+ assert_equal(response.status, 400)
|
||||
+
|
||||
+ # make sure that password is NOT changed
|
||||
+ self._checkpw(testuser, old_password)
|
||||
+
|
||||
def test_pwpolicy_error(self):
|
||||
response = self._changepw(testuser, old_password, '1')
|
||||
|
||||
diff --git a/ipatests/test_ipaserver/test_login_password.py b/ipatests/test_ipaserver/test_login_password.py
|
||||
new file mode 100644
|
||||
index 000000000..9425cb797
|
||||
--- /dev/null
|
||||
+++ b/ipatests/test_ipaserver/test_login_password.py
|
||||
@@ -0,0 +1,88 @@
|
||||
+# Copyright (C) 2023 Red Hat
|
||||
+# see file 'COPYING' for use and warranty information
|
||||
+#
|
||||
+# This program is free software; you can redistribute it and/or modify
|
||||
+# it under the terms of the GNU General Public License as published by
|
||||
+# the Free Software Foundation, either version 3 of the License, or
|
||||
+# (at your option) any later version.
|
||||
+#
|
||||
+# This program is distributed in the hope that it will be useful,
|
||||
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+# GNU General Public License for more details.
|
||||
+#
|
||||
+# You should have received a copy of the GNU General Public License
|
||||
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
+
|
||||
+import os
|
||||
+import pytest
|
||||
+import uuid
|
||||
+
|
||||
+from ipatests.test_ipaserver.httptest import Unauthorized_HTTP_test
|
||||
+from ipatests.test_xmlrpc.xmlrpc_test import XMLRPC_test
|
||||
+from ipatests.util import assert_equal
|
||||
+from ipalib import api, errors
|
||||
+from ipapython.ipautil import run
|
||||
+
|
||||
+testuser = u'tuser'
|
||||
+password = u'password'
|
||||
+
|
||||
+
|
||||
+@pytest.mark.tier1
|
||||
+class test_login_password(XMLRPC_test, Unauthorized_HTTP_test):
|
||||
+ app_uri = '/ipa/session/login_password'
|
||||
+
|
||||
+ @pytest.fixture(autouse=True)
|
||||
+ def login_setup(self, request):
|
||||
+ ccache = os.path.join('/tmp', str(uuid.uuid4()))
|
||||
+ try:
|
||||
+ api.Command['user_add'](uid=testuser, givenname=u'Test', sn=u'User')
|
||||
+ api.Command['passwd'](testuser, password=password)
|
||||
+ run(['kinit', testuser], stdin='{0}\n{0}\n{0}\n'.format(password),
|
||||
+ env={"KRB5CCNAME": ccache})
|
||||
+ except errors.ExecutionError as e:
|
||||
+ pytest.skip(
|
||||
+ 'Cannot set up test user: %s' % e
|
||||
+ )
|
||||
+
|
||||
+ def fin():
|
||||
+ try:
|
||||
+ api.Command['user_del']([testuser])
|
||||
+ except errors.NotFound:
|
||||
+ pass
|
||||
+ os.unlink(ccache)
|
||||
+
|
||||
+ request.addfinalizer(fin)
|
||||
+
|
||||
+ def _login(self, user, password, host=None):
|
||||
+ return self.send_request(params={'user': str(user),
|
||||
+ 'password' : str(password)},
|
||||
+ host=host)
|
||||
+
|
||||
+ def test_bad_options(self):
|
||||
+ for params in (
|
||||
+ None, # no params
|
||||
+ {"user": "foo"}, # missing options
|
||||
+ {"user": "foo", "password": ""}, # empty option
|
||||
+ ):
|
||||
+ response = self.send_request(params=params)
|
||||
+ assert_equal(response.status, 400)
|
||||
+ assert_equal(response.reason, 'Bad Request')
|
||||
+
|
||||
+ def test_invalid_auth(self):
|
||||
+ response = self._login(testuser, 'wrongpassword')
|
||||
+
|
||||
+ assert_equal(response.status, 401)
|
||||
+ assert_equal(response.getheader('X-IPA-Rejection-Reason'),
|
||||
+ 'invalid-password')
|
||||
+
|
||||
+ def test_invalid_referer(self):
|
||||
+ response = self._login(testuser, password, 'attacker.test')
|
||||
+
|
||||
+ assert_equal(response.status, 400)
|
||||
+
|
||||
+ def test_success(self):
|
||||
+ response = self._login(testuser, password)
|
||||
+
|
||||
+ assert_equal(response.status, 200)
|
||||
+ assert response.getheader('X-IPA-Rejection-Reason') is None
|
||||
diff --git a/ipatests/test_ipaserver/test_referer.py b/ipatests/test_ipaserver/test_referer.py
|
||||
new file mode 100644
|
||||
index 000000000..4eade8bba
|
||||
--- /dev/null
|
||||
+++ b/ipatests/test_ipaserver/test_referer.py
|
||||
@@ -0,0 +1,136 @@
|
||||
+# Copyright (C) 2023 Red Hat
|
||||
+# see file 'COPYING' for use and warranty information
|
||||
+#
|
||||
+# This program is free software; you can redistribute it and/or modify
|
||||
+# it under the terms of the GNU General Public License as published by
|
||||
+# the Free Software Foundation, either version 3 of the License, or
|
||||
+# (at your option) any later version.
|
||||
+#
|
||||
+# This program is distributed in the hope that it will be useful,
|
||||
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
+# GNU General Public License for more details.
|
||||
+#
|
||||
+# You should have received a copy of the GNU General Public License
|
||||
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
+
|
||||
+import os
|
||||
+import pytest
|
||||
+import uuid
|
||||
+
|
||||
+from ipatests.test_ipaserver.httptest import Unauthorized_HTTP_test
|
||||
+from ipatests.test_xmlrpc.xmlrpc_test import XMLRPC_test
|
||||
+from ipatests.util import assert_equal
|
||||
+from ipalib import api, errors
|
||||
+from ipapython.ipautil import run
|
||||
+
|
||||
+testuser = u'tuser'
|
||||
+password = u'password'
|
||||
+
|
||||
+
|
||||
+@pytest.mark.tier1
|
||||
+class test_referer(XMLRPC_test, Unauthorized_HTTP_test):
|
||||
+
|
||||
+ @pytest.fixture(autouse=True)
|
||||
+ def login_setup(self, request):
|
||||
+ ccache = os.path.join('/tmp', str(uuid.uuid4()))
|
||||
+ tokenid = None
|
||||
+ try:
|
||||
+ api.Command['user_add'](uid=testuser, givenname=u'Test', sn=u'User')
|
||||
+ api.Command['passwd'](testuser, password=password)
|
||||
+ run(['kinit', testuser], stdin='{0}\n{0}\n{0}\n'.format(password),
|
||||
+ env={"KRB5CCNAME": ccache})
|
||||
+ result = api.Command["otptoken_add"](
|
||||
+ type='HOTP', description='testotp',
|
||||
+ ipatokenotpalgorithm='sha512', ipatokenowner=testuser,
|
||||
+ ipatokenotpdigits='6')
|
||||
+ tokenid = result['result']['ipatokenuniqueid'][0]
|
||||
+ except errors.ExecutionError as e:
|
||||
+ pytest.skip(
|
||||
+ 'Cannot set up test user: %s' % e
|
||||
+ )
|
||||
+
|
||||
+ def fin():
|
||||
+ try:
|
||||
+ api.Command['user_del']([testuser])
|
||||
+ api.Command['otptoken_del']([tokenid])
|
||||
+ except errors.NotFound:
|
||||
+ pass
|
||||
+ os.unlink(ccache)
|
||||
+
|
||||
+ request.addfinalizer(fin)
|
||||
+
|
||||
+ def _request(self, params={}, host=None):
|
||||
+ # implicit is that self.app_uri is set to the appropriate value
|
||||
+ return self.send_request(params=params, host=host)
|
||||
+
|
||||
+ def test_login_password_valid(self):
|
||||
+ """Valid authentication of a user"""
|
||||
+ self.app_uri = "/ipa/session/login_password"
|
||||
+ response = self._request(
|
||||
+ params={'user': 'tuser', 'password': password})
|
||||
+ assert_equal(response.status, 200, self.app_uri)
|
||||
+
|
||||
+ def test_change_password_valid(self):
|
||||
+ """This actually changes the user password"""
|
||||
+ self.app_uri = "/ipa/session/change_password"
|
||||
+ response = self._request(
|
||||
+ params={'user': 'tuser',
|
||||
+ 'old_password': password,
|
||||
+ 'new_password': 'new_password'}
|
||||
+ )
|
||||
+ assert_equal(response.status, 200, self.app_uri)
|
||||
+
|
||||
+ def test_sync_token_valid(self):
|
||||
+ """We aren't testing that sync works, just that we can get there"""
|
||||
+ self.app_uri = "/ipa/session/sync_token"
|
||||
+ response = self._request(
|
||||
+ params={'user': 'tuser',
|
||||
+ 'first_code': '1234',
|
||||
+ 'second_code': '5678',
|
||||
+ 'password': 'password'})
|
||||
+ assert_equal(response.status, 200, self.app_uri)
|
||||
+
|
||||
+ def test_i18n_messages_valid(self):
|
||||
+ # i18n_messages requires a valid JSON request and we send
|
||||
+ # nothing. If we get a 500 error then it got past the
|
||||
+ # referer check.
|
||||
+ self.app_uri = "/ipa/i18n_messages"
|
||||
+ response = self._request()
|
||||
+ assert_equal(response.status, 500, self.app_uri)
|
||||
+
|
||||
+ # /ipa/session/login_x509 is not tested yet as it requires
|
||||
+ # significant additional setup.
|
||||
+ # This can be manually verified by adding
|
||||
+ # Satisfy Any and Require all granted to the configuration
|
||||
+ # section and comment out all Auth directives. The request
|
||||
+ # will fail and log that there is no KRB5CCNAME which comes
|
||||
+ # after the referer check.
|
||||
+
|
||||
+ def test_endpoints_auth_required(self):
|
||||
+ """Test endpoints that require pre-authorization which will
|
||||
+ fail before we even get to the Referer check
|
||||
+ """
|
||||
+ self.endpoints = {
|
||||
+ "/ipa/xml",
|
||||
+ "/ipa/session/login_kerberos",
|
||||
+ "/ipa/session/json",
|
||||
+ "/ipa/session/xml"
|
||||
+ }
|
||||
+ for self.app_uri in self.endpoints:
|
||||
+ response = self._request(host="attacker.test")
|
||||
+
|
||||
+ # referer is checked after auth
|
||||
+ assert_equal(response.status, 401, self.app_uri)
|
||||
+
|
||||
+ def notest_endpoints_invalid(self):
|
||||
+ """Pass in a bad Referer, expect a 400 Bad Request"""
|
||||
+ self.endpoints = {
|
||||
+ "/ipa/session/login_password",
|
||||
+ "/ipa/session/change_password",
|
||||
+ "/ipa/session/sync_token",
|
||||
+ }
|
||||
+ for self.app_uri in self.endpoints:
|
||||
+ response = self._request(host="attacker.test")
|
||||
+
|
||||
+ assert_equal(response.status, 400, self.app_uri)
|
||||
diff --git a/ipatests/util.py b/ipatests/util.py
|
||||
index 5c0152b90..c69d98790 100644
|
||||
--- a/ipatests/util.py
|
||||
+++ b/ipatests/util.py
|
||||
@@ -163,12 +163,12 @@ class ExceptionNotRaised(Exception):
|
||||
return self.msg % self.expected.__name__
|
||||
|
||||
|
||||
-def assert_equal(val1, val2):
|
||||
+def assert_equal(val1, val2, msg=''):
|
||||
"""
|
||||
Assert ``val1`` and ``val2`` are the same type and of equal value.
|
||||
"""
|
||||
assert type(val1) is type(val2), '%r != %r' % (val1, val2)
|
||||
- assert val1 == val2, '%r != %r' % (val1, val2)
|
||||
+ assert val1 == val2, '%r != %r %r' % (val1, val2, msg)
|
||||
|
||||
|
||||
def assert_not_equal(val1, val2):
|
||||
--
|
||||
2.41.0
|
||||
|
@ -1,28 +1,30 @@
|
||||
diff --git a/install/updates/50-krbenctypes.update b/install/updates/50-krbenctypes.update
|
||||
index 1058a92..1bf2bf3 100644
|
||||
--- a/install/updates/50-krbenctypes.update
|
||||
+++ b/install/updates/50-krbenctypes.update
|
||||
@@ -7,3 +7,5 @@ add: krbSupportedEncSaltTypes: aes128-sha2:normal
|
||||
add: krbSupportedEncSaltTypes: aes128-sha2:special
|
||||
add: krbSupportedEncSaltTypes: aes256-sha2:normal
|
||||
add: krbSupportedEncSaltTypes: aes256-sha2:special
|
||||
+remove: krbDefaultEncSaltTypes: des3-hmac-sha1:special
|
||||
+remove: krbDefaultEncSaltTypes: arcfour-hmac:special
|
||||
diff --git a/install/updates/60-trusts.update b/install/updates/60-trusts.update
|
||||
index 56e3920..b2fdcca 100644
|
||||
--- a/install/updates/60-trusts.update
|
||||
+++ b/install/updates/60-trusts.update
|
||||
@@ -54,4 +54,4 @@ add:aci: (target="ldap:///krbprincipalname=cifs/($$dn),cn=services,cn=accounts,$
|
||||
|
||||
# Add the default PAC type to configuration
|
||||
dn: cn=ipaConfig,cn=etc,$SUFFIX
|
||||
-addifnew: ipaKrbAuthzData: MS-PAC
|
||||
+add: ipaKrbAuthzData: MS-PAC
|
||||
From ad4b7f6cedaed54acf279033b650010c65face10 Mon Sep 17 00:00:00 2001
|
||||
From: Sudhir Menon <sumenon@redhat.com>
|
||||
Date: Tue, 20 Aug 2024 14:52:03 +0530
|
||||
Subject: [PATCH] ipatests: Check Default PAC type is added to config
|
||||
|
||||
This patch checks that the default PAC type
|
||||
is added to configuration i.e ipaKrbAuthzData: MS-PAC
|
||||
during ipa-server-installation
|
||||
|
||||
The patch also checks that if 'ipaKrbAuthzData: MS-PAC'
|
||||
attribute is deleted and then when we run 'ipa-server-upgrade'
|
||||
command the attribute is added back.
|
||||
|
||||
Related: https://pagure.io/freeipa/issue/9632
|
||||
|
||||
Signed-off-by: Sudhir Menon <sumenon@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
---
|
||||
.../test_integration/test_installation.py | 15 +++++++++++
|
||||
ipatests/test_integration/test_upgrade.py | 26 ++++++++++++++++++-
|
||||
2 files changed, 40 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ipatests/test_integration/test_installation.py b/ipatests/test_integration/test_installation.py
|
||||
index d41c1ee..ef0727e 100644
|
||||
index ada43e33fe173ea3c315178c37e2a664b05b905b..c5565c452010f23f038ddf329454b591ef09f6af 100644
|
||||
--- a/ipatests/test_integration/test_installation.py
|
||||
+++ b/ipatests/test_integration/test_installation.py
|
||||
@@ -1188,6 +1188,21 @@ class TestInstallMaster(IntegrationTest):
|
||||
@@ -1190,6 +1190,21 @@ class TestInstallMaster(IntegrationTest):
|
||||
expected_stdout=f'href="https://{self.master.hostname}/'
|
||||
)
|
||||
|
||||
@ -45,7 +47,7 @@ index d41c1ee..ef0727e 100644
|
||||
"""
|
||||
Test that --hostname parameter is respected in interactive mode.
|
||||
diff --git a/ipatests/test_integration/test_upgrade.py b/ipatests/test_integration/test_upgrade.py
|
||||
index 182e3b5..8465cf9 100644
|
||||
index 011de939e92790734d63da2f85be1c25349116a8..a0f393780ccc25774466992976532c876aa876da 100644
|
||||
--- a/ipatests/test_integration/test_upgrade.py
|
||||
+++ b/ipatests/test_integration/test_upgrade.py
|
||||
@@ -165,7 +165,6 @@ class TestUpgrade(IntegrationTest):
|
||||
@ -56,10 +58,10 @@ index 182e3b5..8465cf9 100644
|
||||
ldap = self.master.ldap_connect()
|
||||
|
||||
modified = False
|
||||
@@ -477,3 +476,28 @@ class TestUpgrade(IntegrationTest):
|
||||
self.master.run_command(['ipa-server-upgrade'])
|
||||
assert self.master.transport.file_exists(
|
||||
paths.SYSTEMD_PKI_TOMCAT_IPA_CONF)
|
||||
@@ -491,3 +490,28 @@ class TestUpgrade(IntegrationTest):
|
||||
tasks.reinstall_packages(self.master, ['*ipa-client'])
|
||||
assert not self.master.transport.file_exists(
|
||||
paths.SSH_CONFIG + ".orig")
|
||||
+
|
||||
+ def test_mspac_attribute_set(self):
|
||||
+ """
|
||||
@ -85,3 +87,6 @@ index 182e3b5..8465cf9 100644
|
||||
+ result = tasks.ldapsearch_dm(self.master, str(dn),
|
||||
+ ["ipaKrbAuthzData"])
|
||||
+ assert 'ipaKrbAuthzData: MS-PAC' in result.stdout_text
|
||||
--
|
||||
2.46.2
|
||||
|
@ -1,265 +0,0 @@
|
||||
From 013be398bced31f567ef01ac2471cb7529789b4a Mon Sep 17 00:00:00 2001
|
||||
From: Julien Rische <jrische@redhat.com>
|
||||
Date: Mon, 9 Oct 2023 15:47:03 +0200
|
||||
Subject: [PATCH] ipa-kdb: Detect and block Bronze-Bit attacks
|
||||
|
||||
The C8S/RHEL8 version of FreeIPA is vulnerable to the Bronze-Bit attack
|
||||
because it does not implement PAC ticket signature to protect the
|
||||
"forwardable" flag. However, it does implement the PAC extended KDC
|
||||
signature, which protects against PAC spoofing.
|
||||
|
||||
Based on information available in the PAC and the
|
||||
"ok-to-auth-as-delegate" attribute in the database. It is possible to
|
||||
detect and reject requests where the "forwardable" flag was flipped by
|
||||
the attacker in the evidence ticket.
|
||||
---
|
||||
daemons/ipa-kdb/ipa_kdb.h | 13 +++
|
||||
daemons/ipa-kdb/ipa_kdb_kdcpolicy.c | 6 +
|
||||
daemons/ipa-kdb/ipa_kdb_mspac.c | 173 ++++++++++++++++++++++++++++
|
||||
ipaserver/install/server/install.py | 8 ++
|
||||
4 files changed, 200 insertions(+)
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
|
||||
index 7aa5be494..02b2cb631 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb.h
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb.h
|
||||
@@ -367,6 +367,19 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
|
||||
const char *test_realm, size_t size,
|
||||
char **trusted_realm);
|
||||
|
||||
+/* Try to detect a Bronze-Bit attack based on the content of the request and
|
||||
+ * data from the KDB.
|
||||
+ *
|
||||
+ * context krb5 context
|
||||
+ * request KDB request
|
||||
+ * detected Set to "true" if a bronze bit attack is detected and the
|
||||
+ * pointer is not NULL. Remains unset otherwise.
|
||||
+ * status If the call fails and the pointer is not NULL, set it with a
|
||||
+ * message describing the cause of the failure. */
|
||||
+krb5_error_code
|
||||
+ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
|
||||
+ bool *detected, const char **status);
|
||||
+
|
||||
/* DELEGATION CHECKS */
|
||||
|
||||
krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext,
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
|
||||
index f2804c9b2..1032dff0b 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
|
||||
@@ -185,6 +185,12 @@ ipa_kdcpolicy_check_tgs(krb5_context context, krb5_kdcpolicy_moddata moddata,
|
||||
const char **status, krb5_deltat *lifetime_out,
|
||||
krb5_deltat *renew_lifetime_out)
|
||||
{
|
||||
+ krb5_error_code kerr;
|
||||
+
|
||||
+ kerr = ipadb_check_for_bronze_bit_attack(context, request, NULL, status);
|
||||
+ if (kerr)
|
||||
+ return KRB5KDC_ERR_POLICY;
|
||||
+
|
||||
*status = NULL;
|
||||
*lifetime_out = 0;
|
||||
*renew_lifetime_out = 0;
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
index 83cb9914d..b4e22d431 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
@@ -3298,3 +3298,176 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
|
||||
|
||||
return KRB5_KDB_NOENTRY;
|
||||
}
|
||||
+
|
||||
+krb5_error_code
|
||||
+ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
|
||||
+ bool *detected, const char **status)
|
||||
+{
|
||||
+ krb5_error_code kerr;
|
||||
+ const char *st = NULL;
|
||||
+ size_t i, j;
|
||||
+ krb5_ticket *evidence_tkt;
|
||||
+ krb5_authdata **authdata, **ifrel = NULL;
|
||||
+ krb5_pac pac = NULL;
|
||||
+ TALLOC_CTX *tmpctx = NULL;
|
||||
+ krb5_data fullsign = { 0, 0, NULL }, linfo_blob = { 0, 0, NULL };
|
||||
+ DATA_BLOB linfo_data;
|
||||
+ struct PAC_LOGON_INFO_CTR linfo;
|
||||
+ enum ndr_err_code ndr_err;
|
||||
+ struct dom_sid asserted_identity_sid;
|
||||
+ bool evtkt_is_s4u2self = false;
|
||||
+ krb5_db_entry *proxy_entry = NULL;
|
||||
+
|
||||
+ /* If no additional ticket, this is not a constrained delegateion request.
|
||||
+ * Skip checks. */
|
||||
+ if (!(request->kdc_options & KDC_OPT_CNAME_IN_ADDL_TKT)) {
|
||||
+ kerr = 0;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ evidence_tkt = request->second_ticket[0];
|
||||
+
|
||||
+ /* No need to check the Forwardable flag. If it was not set, this request
|
||||
+ * would have failed earlier. */
|
||||
+
|
||||
+ /* We only support general constrained delegation (not RBCD), which is not
|
||||
+ * available for cross-realms. */
|
||||
+ if (!krb5_realm_compare(context, evidence_tkt->server, request->server)) {
|
||||
+ st = "S4U2PROXY_NOT_SUPPORTED_FOR_CROSS_REALMS";
|
||||
+ kerr = ENOTSUP;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ authdata = evidence_tkt->enc_part2->authorization_data;
|
||||
+
|
||||
+ /* Search for the PAC. */
|
||||
+ for (i = 0; authdata != NULL && authdata[i] != NULL; i++) {
|
||||
+ if (authdata[i]->ad_type != KRB5_AUTHDATA_IF_RELEVANT)
|
||||
+ continue;
|
||||
+
|
||||
+ kerr = krb5_decode_authdata_container(context,
|
||||
+ KRB5_AUTHDATA_IF_RELEVANT,
|
||||
+ authdata[i], &ifrel);
|
||||
+ if (kerr) {
|
||||
+ st = "S4U2PROXY_CANNOT_DECODE_EVIDENCE_TKT_AUTHDATA";
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ for (j = 0; ifrel[j] != NULL; j++) {
|
||||
+ if (ifrel[j]->ad_type == KRB5_AUTHDATA_WIN2K_PAC)
|
||||
+ break;
|
||||
+ }
|
||||
+ if (ifrel[j] != NULL)
|
||||
+ break;
|
||||
+
|
||||
+ krb5_free_authdata(context, ifrel);
|
||||
+ ifrel = NULL;
|
||||
+ }
|
||||
+
|
||||
+ if (ifrel == NULL) {
|
||||
+ st = "S4U2PROXY_EVIDENCE_TKT_WITHOUT_PAC";
|
||||
+ kerr = ENOENT;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ /* Parse the PAC. */
|
||||
+ kerr = krb5_pac_parse(context, ifrel[j]->contents, ifrel[j]->length, &pac);
|
||||
+ if (kerr) {
|
||||
+ st = "S4U2PROXY_CANNOT_DECODE_EVICENCE_TKT_PAC";
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ /* Check that the PAC extanded KDC signature is present. If it is, it was
|
||||
+ * already tested.
|
||||
+ * If absent, the context of the PAC cannot be trusted. */
|
||||
+ kerr = krb5_pac_get_buffer(context, pac, KRB5_PAC_FULL_CHECKSUM, &fullsign);
|
||||
+ if (kerr) {
|
||||
+ st = "S4U2PROXY_MISSING_EXTENDED_KDC_SIGN_IN_EVIDENCE_TKT_PAC";
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ /* Get the PAC Logon Info. */
|
||||
+ kerr = krb5_pac_get_buffer(context, pac, KRB5_PAC_LOGON_INFO, &linfo_blob);
|
||||
+ if (kerr) {
|
||||
+ st = "S4U2PROXY_NO_PAC_LOGON_INFO_IN_EVIDENCE_TKT";
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ /* Parse the PAC Logon Info. */
|
||||
+ tmpctx = talloc_new(NULL);
|
||||
+ if (!tmpctx) {
|
||||
+ st = "OUT_OF_MEMORY";
|
||||
+ kerr = ENOMEM;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ linfo_data.length = linfo_blob.length;
|
||||
+ linfo_data.data = (uint8_t *)linfo_blob.data;
|
||||
+ ndr_err = ndr_pull_union_blob(&linfo_data, tmpctx, &linfo,
|
||||
+ PAC_TYPE_LOGON_INFO,
|
||||
+ (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
|
||||
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
|
||||
+ st = "S4U2PROXY_CANNOT_PARSE_ENVIDENCE_TKT_PAC_LOGON_INFO";
|
||||
+ kerr = EINVAL;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ /* Check that the extra SIDs array is not empty. */
|
||||
+ if (linfo.info->info3.sidcount == 0) {
|
||||
+ st = "S4U2PROXY_NO_EXTRA_SID";
|
||||
+ kerr = ENOENT;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ /* Search for the S-1-18-2 domain SID, which indicates the ticket was
|
||||
+ * obtained using S4U2Self */
|
||||
+ kerr = ipadb_string_to_sid("S-1-18-2", &asserted_identity_sid);
|
||||
+ if (kerr) {
|
||||
+ st = "S4U2PROXY_CANNOT_CREATE_ASSERTED_IDENTITY_SID";
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < linfo.info->info3.sidcount; i++) {
|
||||
+ if (dom_sid_check(&asserted_identity_sid,
|
||||
+ linfo.info->info3.sids[0].sid, true)) {
|
||||
+ evtkt_is_s4u2self = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* If the ticket was obtained using S4U2Self, the proxy principal entry must
|
||||
+ * have the "ok_to_auth_as_delegate" attribute set to true. */
|
||||
+ if (evtkt_is_s4u2self) {
|
||||
+ kerr = ipadb_get_principal(context, evidence_tkt->server, 0,
|
||||
+ &proxy_entry);
|
||||
+ if (kerr) {
|
||||
+ st = "S4U2PROXY_CANNOT_FIND_PROXY_PRINCIPAL";
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ if (!(proxy_entry->attributes & KRB5_KDB_OK_TO_AUTH_AS_DELEGATE)) {
|
||||
+ /* This evidence ticket cannot be forwardable given the privileges
|
||||
+ * of the proxy principal.
|
||||
+ * This is a Bronze Bit attack. */
|
||||
+ if (detected)
|
||||
+ *detected = true;
|
||||
+ st = "S4U2PROXY_BRONZE_BIT_ATTACK_DETECTED";
|
||||
+ kerr = EBADE;
|
||||
+ goto end;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ kerr = 0;
|
||||
+
|
||||
+end:
|
||||
+ if (st && status)
|
||||
+ *status = st;
|
||||
+
|
||||
+ krb5_free_authdata(context, ifrel);
|
||||
+ krb5_pac_free(context, pac);
|
||||
+ krb5_free_data_contents(context, &linfo_blob);
|
||||
+ krb5_free_data_contents(context, &fullsign);
|
||||
+ talloc_free(tmpctx);
|
||||
+ ipadb_free_principal(context, proxy_entry);
|
||||
+ return kerr;
|
||||
+}
|
||||
diff --git a/ipaserver/install/server/install.py b/ipaserver/install/server/install.py
|
||||
index 4e4076410..bfbb83bcb 100644
|
||||
--- a/ipaserver/install/server/install.py
|
||||
+++ b/ipaserver/install/server/install.py
|
||||
@@ -981,6 +981,14 @@ def install(installer):
|
||||
# Set the admin user kerberos password
|
||||
ds.change_admin_password(admin_password)
|
||||
|
||||
+ # Force KDC to refresh the cached value of ipaKrbAuthzData by restarting.
|
||||
+ # ipaKrbAuthzData has to be set with "MS-PAC" to trigger PAC generation,
|
||||
+ # which is required to handle S4U2Proxy with the Bronze-Bit fix.
|
||||
+ # Not doing so would cause API malfunction for around a minute, which is
|
||||
+ # long enough to cause the hereafter client installation to fail.
|
||||
+ service.print_msg("Restarting the KDC")
|
||||
+ krb.restart()
|
||||
+
|
||||
# Call client install script
|
||||
service.print_msg("Configuring client side components")
|
||||
try:
|
||||
--
|
||||
2.41.0
|
||||
|
@ -0,0 +1,86 @@
|
||||
From 42eb97ee6bd8011b590aef321d4386ea9352933d Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Wed, 28 Aug 2024 10:02:19 +0300
|
||||
Subject: [PATCH] selinux: add all IPA log files to ipa_log_t file context
|
||||
|
||||
We have multiple log files that produced by IPA components. Some of them
|
||||
are written by the tools that run as root and inherit their file context
|
||||
from /var/log -> var_log_t. However, increasingly we get tools that were
|
||||
run through oddjob helpers. These supposed to be run within ipa_helper_t
|
||||
SELinux context which has write permissions for ipa_log_t file context.
|
||||
|
||||
Add all known log files from the base platform. The following script was
|
||||
used to generate them:
|
||||
$ git grep '_LOG = .*ipa.*\.log' ipaplatform/base/paths.py | cut -d= -f2 | \
|
||||
xargs -I% echo -e "%\t--\tgen_context(system_u:object_r:ipa_log_t,s0)"
|
||||
|
||||
/var/log/ipabackup.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
/var/log/ipaclient-install.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
/var/log/ipaclient-uninstall.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
/var/log/ipaclientsamba-install.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
/var/log/ipaclientsamba-uninstall.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
/var/log/ipareplica-ca-install.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
/var/log/ipareplica-conncheck.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
/var/log/ipareplica-install.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
/var/log/iparestore.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
/var/log/ipaserver-enable-sid.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
/var/log/ipaserver-install.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
/var/log/ipaserver-adtrust-install.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
/var/log/ipaserver-dns-install.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
/var/log/ipaserver-kra-install.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
/var/log/ipaserver-uninstall.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
/var/log/ipaupgrade.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
/var/log/ipatrust-enable-agent.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
/var/log/ipaepn.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
/var/log/ipa-custodia.audit.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
/var/log/ipa-migrate.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
|
||||
ipa-custodia.audit.log was already in the present list.
|
||||
|
||||
Additionally, ipa-migrate-conflict.ldif is used by the ipa-migrate tool
|
||||
but is not provided through the ipaplatform mechanism. It is added
|
||||
explicitly.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9654
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
---
|
||||
selinux/ipa.fc | 21 ++++++++++++++++++++-
|
||||
1 file changed, 20 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/selinux/ipa.fc b/selinux/ipa.fc
|
||||
index 700e3a14a11fcd403a2e6f57ec781c58dae77660..47bd19ba77418cad1f0904dc4a9a35ce9d6ff9d2 100644
|
||||
--- a/selinux/ipa.fc
|
||||
+++ b/selinux/ipa.fc
|
||||
@@ -24,7 +24,26 @@
|
||||
|
||||
/var/log/ipa(/.*)? gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
|
||||
-/var/log/ipareplica-conncheck.log.* -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
+/var/log/ipabackup.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
+/var/log/ipaclient-install.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
+/var/log/ipaclient-uninstall.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
+/var/log/ipaclientsamba-install.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
+/var/log/ipaclientsamba-uninstall.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
+/var/log/ipareplica-ca-install.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
+/var/log/ipareplica-conncheck.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
+/var/log/ipareplica-install.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
+/var/log/iparestore.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
+/var/log/ipaserver-enable-sid.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
+/var/log/ipaserver-install.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
+/var/log/ipaserver-adtrust-install.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
+/var/log/ipaserver-dns-install.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
+/var/log/ipaserver-kra-install.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
+/var/log/ipaserver-uninstall.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
+/var/log/ipaupgrade.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
+/var/log/ipatrust-enable-agent.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
+/var/log/ipaepn.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
+/var/log/ipa-migrate.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
+/var/log/ipa-migrate-conflict.ldif -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
|
||||
/var/run/ipa(/.*)? gen_context(system_u:object_r:ipa_var_run_t,s0)
|
||||
|
||||
--
|
||||
2.46.2
|
||||
|
@ -1,25 +1,54 @@
|
||||
From aa4651526e6697e15ce4960bf1d15d1389889c7f Mon Sep 17 00:00:00 2001
|
||||
From: "asharov@redhat.com" <asharov@redhat.com>
|
||||
Date: Mon, 24 Jun 2024 15:33:34 +0200
|
||||
Subject: [PATCH] Add ipa-idrange-fix
|
||||
|
||||
ipa-idrange-fix is a tool for analysis of existing IPA ranges, users
|
||||
and groups outside of those ranges, and functionality to propose
|
||||
and apply remediations to make sure as much users and groups as
|
||||
possible end up in the IPA-managed ranges.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9612
|
||||
|
||||
Signed-off-by: Aleksandr Sharov <asharov@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
freeipa.spec.in | 2 +
|
||||
install/tools/Makefile.am | 2 +
|
||||
install/tools/ipa-idrange-fix.in | 8 +
|
||||
install/tools/man/Makefile.am | 1 +
|
||||
install/tools/man/ipa-idrange-fix.1 | 111 ++
|
||||
ipaserver/install/ipa_idrange_fix.py | 1085 +++++++++++++++++
|
||||
.../test_integration/test_ipa_idrange_fix.py | 189 +++
|
||||
7 files changed, 1398 insertions(+)
|
||||
create mode 100644 install/tools/ipa-idrange-fix.in
|
||||
create mode 100644 install/tools/man/ipa-idrange-fix.1
|
||||
create mode 100644 ipaserver/install/ipa_idrange_fix.py
|
||||
create mode 100644 ipatests/test_integration/test_ipa_idrange_fix.py
|
||||
|
||||
diff --git a/freeipa.spec.in b/freeipa.spec.in
|
||||
index 086e8c7..11a5607 100755
|
||||
index e370290bc74d92ab239bf11e88b3fa7e4faef415..171b6ad27b57553fdd46c7d041715949bb00b163 100755
|
||||
--- a/freeipa.spec.in
|
||||
+++ b/freeipa.spec.in
|
||||
@@ -1395,6 +1395,7 @@ fi
|
||||
@@ -1517,6 +1517,7 @@ fi
|
||||
%{_sbindir}/ipa-pkinit-manage
|
||||
%{_sbindir}/ipa-crlgen-manage
|
||||
%{_sbindir}/ipa-cert-fix
|
||||
+%{_sbindir}/ipa-idrange-fix
|
||||
%{_sbindir}/ipa-acme-manage
|
||||
%{_libexecdir}/certmonger/dogtag-ipa-ca-renew-agent-submit
|
||||
%{_libexecdir}/certmonger/ipa-server-guard
|
||||
@@ -1470,6 +1471,7 @@ fi
|
||||
%{_sbindir}/ipa-migrate
|
||||
%if 0%{?fedora} >= 38
|
||||
@@ -1596,6 +1597,7 @@ fi
|
||||
%{_mandir}/man1/ipa-pkinit-manage.1*
|
||||
%{_mandir}/man1/ipa-crlgen-manage.1*
|
||||
%{_mandir}/man1/ipa-cert-fix.1*
|
||||
+%{_mandir}/man1/ipa-idrange-fix.1*
|
||||
%{_mandir}/man1/ipa-acme-manage.1*
|
||||
|
||||
%{_mandir}/man1/ipa-migrate.1*
|
||||
|
||||
diff --git a/install/tools/Makefile.am b/install/tools/Makefile.am
|
||||
index 5f36742..ad56cfa 100644
|
||||
index c454fad9795c79f88e1d72688f1d15c5234cc113..ca484ec37969c9c06ae7b408b55fa30cd4e8e4fe 100644
|
||||
--- a/install/tools/Makefile.am
|
||||
+++ b/install/tools/Makefile.am
|
||||
@@ -31,6 +31,7 @@ dist_noinst_DATA = \
|
||||
@ -30,17 +59,17 @@ index 5f36742..ad56cfa 100644
|
||||
ipa-custodia.in \
|
||||
ipa-custodia-check.in \
|
||||
ipa-httpd-kdcproxy.in \
|
||||
@@ -67,6 +68,7 @@ nodist_sbin_SCRIPTS = \
|
||||
@@ -68,6 +69,7 @@ nodist_sbin_SCRIPTS = \
|
||||
ipa-pkinit-manage \
|
||||
ipa-crlgen-manage \
|
||||
ipa-cert-fix \
|
||||
+ ipa-idrange-fix \
|
||||
ipa-acme-manage \
|
||||
ipa-migrate \
|
||||
$(NULL)
|
||||
|
||||
diff --git a/install/tools/ipa-idrange-fix.in b/install/tools/ipa-idrange-fix.in
|
||||
new file mode 100644
|
||||
index 0000000..5994bd2
|
||||
index 0000000000000000000000000000000000000000..5994bd28b15e247c5a086238f36b16cc75ff24c3
|
||||
--- /dev/null
|
||||
+++ b/install/tools/ipa-idrange-fix.in
|
||||
@@ -0,0 +1,8 @@
|
||||
@ -53,7 +82,7 @@ index 0000000..5994bd2
|
||||
+
|
||||
+IPAIDRangeFix.run_cli()
|
||||
diff --git a/install/tools/man/Makefile.am b/install/tools/man/Makefile.am
|
||||
index d1ea046..b9bbd04 100644
|
||||
index 34f359863afca7b6c1e792a53afc25bb8eb41fd3..e9542a77bbbb88054eae1e64311d6e9ec5bee499 100644
|
||||
--- a/install/tools/man/Makefile.am
|
||||
+++ b/install/tools/man/Makefile.am
|
||||
@@ -29,6 +29,7 @@ dist_man1_MANS = \
|
||||
@ -62,11 +91,11 @@ index d1ea046..b9bbd04 100644
|
||||
ipa-cert-fix.1 \
|
||||
+ ipa-idrange-fix.1 \
|
||||
ipa-acme-manage.1 \
|
||||
$(NULL)
|
||||
|
||||
ipa-migrate.1 \
|
||||
$(NULL)
|
||||
diff --git a/install/tools/man/ipa-idrange-fix.1 b/install/tools/man/ipa-idrange-fix.1
|
||||
new file mode 100644
|
||||
index 0000000..178d2e8
|
||||
index 0000000000000000000000000000000000000000..178d2e88779e135a65f3285de62d2dc3b19c175a
|
||||
--- /dev/null
|
||||
+++ b/install/tools/man/ipa-idrange-fix.1
|
||||
@@ -0,0 +1,111 @@
|
||||
@ -183,7 +212,7 @@ index 0000000..178d2e8
|
||||
+.BR ipa\ idrange-add(1)
|
||||
diff --git a/ipaserver/install/ipa_idrange_fix.py b/ipaserver/install/ipa_idrange_fix.py
|
||||
new file mode 100644
|
||||
index 0000000..c6c67ae
|
||||
index 0000000000000000000000000000000000000000..c6c67ae9330e2d0184efc09d09a84216ef0772a6
|
||||
--- /dev/null
|
||||
+++ b/ipaserver/install/ipa_idrange_fix.py
|
||||
@@ -0,0 +1,1085 @@
|
||||
@ -1274,7 +1303,7 @@ index 0000000..c6c67ae
|
||||
+# endregion
|
||||
diff --git a/ipatests/test_integration/test_ipa_idrange_fix.py b/ipatests/test_integration/test_ipa_idrange_fix.py
|
||||
new file mode 100644
|
||||
index 0000000..ff8fbda
|
||||
index 0000000000000000000000000000000000000000..de3da9bfd221ce74f1d1bbb0dbe12e4db08b8daa
|
||||
--- /dev/null
|
||||
+++ b/ipatests/test_integration/test_ipa_idrange_fix.py
|
||||
@@ -0,0 +1,189 @@
|
||||
@ -1352,7 +1381,7 @@ index 0000000..ff8fbda
|
||||
+ "idrange_reversed",
|
||||
+ "--base-id", '50000',
|
||||
+ "--range-size", '20000',
|
||||
+ "--rid-base", '100300000',
|
||||
+ "--rid-base", '100300000'
|
||||
+ "--secondary-rid-base", '301000'
|
||||
+ ])
|
||||
+
|
||||
@ -1467,73 +1496,6 @@ index 0000000..ff8fbda
|
||||
+
|
||||
+ assert expected_text in result.stderr_text
|
||||
+ assert expected_user in result.stderr_text
|
||||
diff --git a/ipatests/prci_definitions/nightly_ipa-4-9_latest.yaml b/ipatests/prci_definitions/nightly_ipa-4-9_latest.yaml
|
||||
index 7c03a48..4021d3b 100644
|
||||
--- a/ipatests/prci_definitions/nightly_ipa-4-9_latest.yaml
|
||||
+++ b/ipatests/prci_definitions/nightly_ipa-4-9_latest.yaml
|
||||
@@ -1766,6 +1766,18 @@ jobs:
|
||||
timeout: 10800
|
||||
topology: *master_1repl
|
||||
|
||||
+ fedora-latest-ipa-4-9/test_idrange_fix:
|
||||
+ requires: [fedora-latest-ipa-4-9/build]
|
||||
+ priority: 50
|
||||
+ job:
|
||||
+ class: RunPytest
|
||||
+ args:
|
||||
+ build_url: '{fedora-latest-ipa-4-9/build_url}'
|
||||
+ test_suite: test_integration/test_ipa_idrange_fix.py
|
||||
+ template: *ci-ipa-4-9-latest
|
||||
+ timeout: 3600
|
||||
+ topology: *ipaserver
|
||||
+
|
||||
fedora-latest-ipa-4-9/test_subids:
|
||||
requires: [fedora-latest-ipa-4-9/build]
|
||||
priority: 50
|
||||
diff --git a/ipatests/prci_definitions/nightly_ipa-4-9_latest_selinux.yaml b/ipatests/prci_definitions/nightly_ipa-4-9_latest_selinux.yaml
|
||||
index 802bd2a..d24aaa8 100644
|
||||
--- a/ipatests/prci_definitions/nightly_ipa-4-9_latest_selinux.yaml
|
||||
+++ b/ipatests/prci_definitions/nightly_ipa-4-9_latest_selinux.yaml
|
||||
@@ -1906,6 +1906,19 @@ jobs:
|
||||
timeout: 10800
|
||||
topology: *master_1repl
|
||||
|
||||
+ fedora-latest-ipa-4-9/test_idrange_fix:
|
||||
+ requires: [fedora-latest-ipa-4-9/build]
|
||||
+ priority: 50
|
||||
+ job:
|
||||
+ class: RunPytest
|
||||
+ args:
|
||||
+ build_url: '{fedora-latest-ipa-4-9/build_url}'
|
||||
+ selinux_enforcing: True
|
||||
+ test_suite: test_integration/test_ipa_idrange_fix.py
|
||||
+ template: *ci-ipa-4-9-latest
|
||||
+ timeout: 3600
|
||||
+ topology: *ipaserver
|
||||
+
|
||||
fedora-latest-ipa-4-9/test_subids:
|
||||
requires: [fedora-latest-ipa-4-9/build]
|
||||
priority: 50
|
||||
diff --git a/ipatests/prci_definitions/nightly_ipa-4-9_previous.yaml b/ipatests/prci_definitions/nightly_ipa-4-9_previous.yaml
|
||||
index 1e1adb8..b0efd57 100644
|
||||
--- a/ipatests/prci_definitions/nightly_ipa-4-9_previous.yaml
|
||||
+++ b/ipatests/prci_definitions/nightly_ipa-4-9_previous.yaml
|
||||
@@ -1766,6 +1766,18 @@ jobs:
|
||||
timeout: 10800
|
||||
topology: *master_1repl
|
||||
|
||||
+ fedora-previous-ipa-4-9/test_idrange_fix:
|
||||
+ requires: [fedora-previous-ipa-4-9/build]
|
||||
+ priority: 50
|
||||
+ job:
|
||||
+ class: RunPytest
|
||||
+ args:
|
||||
+ build_url: '{fedora-previous-ipa-4-9/build_url}'
|
||||
+ test_suite: test_integration/test_ipa_idrange_fix.py
|
||||
+ template: *ci-ipa-4-9-previous
|
||||
+ timeout: 3600
|
||||
+ topology: *ipaserver
|
||||
+
|
||||
fedora-previous-ipa-4-9/test_subids:
|
||||
requires: [fedora-previous-ipa-4-9/build]
|
||||
priority: 50
|
||||
--
|
||||
2.46.2
|
||||
|
@ -1,212 +0,0 @@
|
||||
From 3add9ba03a0af913d03b1f5ecaa8e48e46a93f91 Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Jan 15 2024 13:42:08 +0000
|
||||
Subject: Server affinity: Retain user-requested remote server
|
||||
|
||||
|
||||
We want to avoid splitting a replica server installation between
|
||||
two hosts where possible so if a CA or KRA is requested then
|
||||
we only try to install against a remote server that also provides
|
||||
those capabilities. This avoids race conditions.
|
||||
|
||||
If a CA or KRA is not requested and the user has provided a
|
||||
server to install against then use that instead of overriding it.
|
||||
|
||||
Extend the logic of picking the remote Custodia mode
|
||||
(KRA, CA, *MASTER*) to include considering whether the
|
||||
CA and KRA services are requested. If the service(s) are
|
||||
not requested the the associated hostname may not be
|
||||
reliable.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9491
|
||||
Related: https://pagure.io/freeipa/issue/9289
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
|
||||
index 27fbdef..8096b6a 100644
|
||||
--- a/ipaserver/install/server/replicainstall.py
|
||||
+++ b/ipaserver/install/server/replicainstall.py
|
||||
@@ -782,6 +782,7 @@ def promotion_check_host_principal_auth_ind(conn, hostdn):
|
||||
|
||||
|
||||
def remote_connection(config):
|
||||
+ logger.debug("Creating LDAP connection to %s", config.master_host_name)
|
||||
ldapuri = 'ldaps://%s' % ipautil.format_netloc(config.master_host_name)
|
||||
xmlrpc_uri = 'https://{}/ipa/xml'.format(
|
||||
ipautil.format_netloc(config.master_host_name))
|
||||
@@ -1087,7 +1088,7 @@ def promote_check(installer):
|
||||
'CA', conn, preferred_cas
|
||||
)
|
||||
if ca_host is not None:
|
||||
- if config.master_host_name != ca_host:
|
||||
+ if options.setup_ca and config.master_host_name != ca_host:
|
||||
conn.disconnect()
|
||||
del remote_api
|
||||
config.master_host_name = ca_host
|
||||
@@ -1096,8 +1097,7 @@ def promote_check(installer):
|
||||
conn = remote_api.Backend.ldap2
|
||||
conn.connect(ccache=installer._ccache)
|
||||
config.ca_host_name = ca_host
|
||||
- config.master_host_name = ca_host
|
||||
- ca_enabled = True
|
||||
+ ca_enabled = True # There is a CA somewhere in the topology
|
||||
if options.dirsrv_cert_files:
|
||||
logger.error("Certificates could not be provided when "
|
||||
"CA is present on some master.")
|
||||
@@ -1135,7 +1135,7 @@ def promote_check(installer):
|
||||
'KRA', conn, preferred_kras
|
||||
)
|
||||
if kra_host is not None:
|
||||
- if config.master_host_name != kra_host:
|
||||
+ if options.setup_kra and config.master_host_name != kra_host:
|
||||
conn.disconnect()
|
||||
del remote_api
|
||||
config.master_host_name = kra_host
|
||||
@@ -1143,10 +1143,9 @@ def promote_check(installer):
|
||||
installer._remote_api = remote_api
|
||||
conn = remote_api.Backend.ldap2
|
||||
conn.connect(ccache=installer._ccache)
|
||||
- config.kra_host_name = kra_host
|
||||
- config.ca_host_name = kra_host
|
||||
- config.master_host_name = kra_host
|
||||
- kra_enabled = True
|
||||
+ config.kra_host_name = kra_host
|
||||
+ config.ca_host_name = kra_host
|
||||
+ kra_enabled = True # There is a KRA somewhere in the topology
|
||||
if options.setup_kra and options.server and \
|
||||
kra_host != options.server:
|
||||
# Installer was provided with a specific master
|
||||
@@ -1372,10 +1371,10 @@ def install(installer):
|
||||
otpd.create_instance('OTPD', config.host_name,
|
||||
ipautil.realm_to_suffix(config.realm_name))
|
||||
|
||||
- if kra_enabled:
|
||||
+ if options.setup_kra and kra_enabled:
|
||||
# A KRA peer always provides a CA, too.
|
||||
mode = custodiainstance.CustodiaModes.KRA_PEER
|
||||
- elif ca_enabled:
|
||||
+ elif options.setup_ca and ca_enabled:
|
||||
mode = custodiainstance.CustodiaModes.CA_PEER
|
||||
else:
|
||||
mode = custodiainstance.CustodiaModes.MASTER_PEER
|
||||
|
||||
From 701339d4fed539713eb1a13495992879f56a6daa Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Jan 18 2024 14:53:28 +0000
|
||||
Subject: Server affinity: Don't rely just on [ca|kra]_enabled for installs
|
||||
|
||||
|
||||
ca_enable and kra_enabled are intended to be used to identify that
|
||||
a CA or KRA is available in the topology. It was also being used
|
||||
to determine whether a CA or KRA service is desired on a replica
|
||||
install, rather than options.setup_[ca|kra]
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9510
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
|
||||
index 8096b6a..191913d 100644
|
||||
--- a/ipaserver/install/server/replicainstall.py
|
||||
+++ b/ipaserver/install/server/replicainstall.py
|
||||
@@ -1143,7 +1143,8 @@ def promote_check(installer):
|
||||
installer._remote_api = remote_api
|
||||
conn = remote_api.Backend.ldap2
|
||||
conn.connect(ccache=installer._ccache)
|
||||
- config.kra_host_name = kra_host
|
||||
+ config.kra_host_name = kra_host
|
||||
+ if options.setup_kra: # only reset ca_host if KRA is requested
|
||||
config.ca_host_name = kra_host
|
||||
kra_enabled = True # There is a KRA somewhere in the topology
|
||||
if options.setup_kra and options.server and \
|
||||
@@ -1381,7 +1382,7 @@ def install(installer):
|
||||
custodia = custodiainstance.get_custodia_instance(config, mode)
|
||||
custodia.create_instance()
|
||||
|
||||
- if ca_enabled:
|
||||
+ if options.setup_ca and ca_enabled:
|
||||
options.realm_name = config.realm_name
|
||||
options.domain_name = config.domain_name
|
||||
options.host_name = config.host_name
|
||||
@@ -1397,7 +1398,7 @@ def install(installer):
|
||||
service.print_msg("Finalize replication settings")
|
||||
ds.finalize_replica_config()
|
||||
|
||||
- if kra_enabled:
|
||||
+ if options.setup_kra and kra_enabled:
|
||||
kra.install(api, config, options, custodia=custodia)
|
||||
|
||||
service.print_msg("Restarting the KDC")
|
||||
|
||||
From e6014a5c1996528b255480b67fe2937203bff81b Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Jan 23 2024 15:32:58 +0000
|
||||
Subject: Server affinity: call ca.install() if there is a CA in the topology
|
||||
|
||||
|
||||
This should not have been gated on options.setup_ca because we need
|
||||
the RA agent on all servers if there is a CA in the topology otherwise
|
||||
the non-CA servers won't be able to communicate with the CA.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9510
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py
|
||||
index c93ae1f..187f803 100644
|
||||
--- a/ipaserver/install/ca.py
|
||||
+++ b/ipaserver/install/ca.py
|
||||
@@ -387,9 +387,10 @@ def install_step_0(standalone, replica_config, options, custodia):
|
||||
promote = False
|
||||
else:
|
||||
cafile = os.path.join(replica_config.dir, 'cacert.p12')
|
||||
- custodia.get_ca_keys(
|
||||
- cafile,
|
||||
- replica_config.dirman_password)
|
||||
+ if replica_config.setup_ca:
|
||||
+ custodia.get_ca_keys(
|
||||
+ cafile,
|
||||
+ replica_config.dirman_password)
|
||||
|
||||
ca_signing_algorithm = None
|
||||
ca_type = None
|
||||
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
|
||||
index f8d4733..4c1c07c 100644
|
||||
--- a/ipaserver/install/server/replicainstall.py
|
||||
+++ b/ipaserver/install/server/replicainstall.py
|
||||
@@ -1359,11 +1359,13 @@ def install(installer):
|
||||
custodia = custodiainstance.get_custodia_instance(config, mode)
|
||||
custodia.create_instance()
|
||||
|
||||
- if options.setup_ca and ca_enabled:
|
||||
+ if ca_enabled:
|
||||
options.realm_name = config.realm_name
|
||||
options.domain_name = config.domain_name
|
||||
options.host_name = config.host_name
|
||||
options.dm_password = config.dirman_password
|
||||
+ # Always call ca.install() if there is a CA in the topology
|
||||
+ # to ensure the RA agent is present.
|
||||
ca.install(False, config, options, custodia=custodia)
|
||||
|
||||
# configure PKINIT now that all required services are in place
|
||||
@@ -1375,7 +1377,8 @@ def install(installer):
|
||||
service.print_msg("Finalize replication settings")
|
||||
ds.finalize_replica_config()
|
||||
|
||||
- if options.setup_kra and kra_enabled:
|
||||
+ if kra_enabled:
|
||||
+ # The KRA installer checks for itself the status of setup_kra
|
||||
kra.install(api, config, options, custodia=custodia)
|
||||
|
||||
service.print_msg("Restarting the KDC")
|
||||
|
@ -1,97 +0,0 @@
|
||||
From 3842116185de6ae8714f30b57bd75c7eddde53d8 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Jan 15 2024 13:50:10 +0000
|
||||
Subject: host: update System: Manage Host Keytab permission
|
||||
|
||||
|
||||
Since commit 5c0e7a5fb420377dcc06a956695afdcb35196444, a new extended
|
||||
operation to get a keytab is supposed to be used. This keytab
|
||||
setting/retrieval extended operation checks access rights of the bound
|
||||
DN to write to a virtual attribute 'ipaProtectedOperation;write_keys'.
|
||||
|
||||
If the write isn't allowed, the operation is rejected and ipa-getkeytab
|
||||
tool falls back to an older code that generates the keytab on the client
|
||||
and forcibly sets to the LDAP entry. For the latter, a check is done to
|
||||
make sure the bound DN is allowed to write to 'krbPrincipalKey' attribute.
|
||||
|
||||
This fallback should never happen for newer deployments. When enrollemnt
|
||||
operation is delegated to non-administrative user with the help of 'Host
|
||||
Enrollment' role, a host can be pre-created or created at enrollment
|
||||
time, if this non-administrative user has 'Host Administrators' role. In
|
||||
the latter case a system permission 'System: Manage Host Keytab' grants
|
||||
write access to 'krbPrincipalKey' attribute but lacks any access to the
|
||||
virtual attributes expected by the new extended operation.
|
||||
|
||||
There is a second virtual attribute, 'ipaProtectedOperation;read_keys',
|
||||
that allows to retrieve existing keys for a host. However, during
|
||||
initial enrollment we do not allow to retrieve and reuse existing
|
||||
Kerberos key: while 'ipa-getkeytab -r' would give ability to retrieve
|
||||
the existing key, 'ipa-join' has no way to trigger that operation.
|
||||
Hence, permission 'System: Manage Host Keytab' will not grant the right
|
||||
to read the Kerberos key via extended operation used by 'ipa-getkeytab
|
||||
-r'. Such operation can be done later by utilizing 'ipa
|
||||
service/host-allow-retrieve-keytab' commands.
|
||||
|
||||
Fix 'System: Manage Host Keytab' permission and extend a permission test
|
||||
to see that we do not fallback to the old extended operation.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9496
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/ACI.txt b/ACI.txt
|
||||
index e6d6e3d..236bb43 100644
|
||||
--- a/ACI.txt
|
||||
+++ b/ACI.txt
|
||||
@@ -147,7 +147,7 @@ aci: (targetattr = "usercertificate")(targetfilter = "(objectclass=ipahost)")(ve
|
||||
dn: cn=computers,cn=accounts,dc=ipa,dc=example
|
||||
aci: (targetattr = "userpassword")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Manage Host Enrollment Password";allow (write) groupdn = "ldap:///cn=System: Manage Host Enrollment Password,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||
dn: cn=computers,cn=accounts,dc=ipa,dc=example
|
||||
-aci: (targetattr = "krblastpwdchange || krbprincipalkey")(targetfilter = "(&(!(memberOf=cn=ipaservers,cn=hostgroups,cn=accounts,dc=ipa,dc=example))(objectclass=ipahost))")(version 3.0;acl "permission:System: Manage Host Keytab";allow (write) groupdn = "ldap:///cn=System: Manage Host Keytab,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||
+aci: (targetattr = "ipaprotectedoperation;write_keys || krblastpwdchange || krbprincipalkey")(targetfilter = "(&(!(memberOf=cn=ipaservers,cn=hostgroups,cn=accounts,dc=ipa,dc=example))(objectclass=ipahost))")(version 3.0;acl "permission:System: Manage Host Keytab";allow (write) groupdn = "ldap:///cn=System: Manage Host Keytab,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||
dn: cn=computers,cn=accounts,dc=ipa,dc=example
|
||||
aci: (targetattr = "createtimestamp || entryusn || ipaallowedtoperform;read_keys || ipaallowedtoperform;write_keys || modifytimestamp || objectclass")(targetfilter = "(objectclass=ipahost)")(version 3.0;acl "permission:System: Manage Host Keytab Permissions";allow (compare,read,search,write) groupdn = "ldap:///cn=System: Manage Host Keytab Permissions,cn=permissions,cn=pbac,dc=ipa,dc=example";)
|
||||
dn: cn=computers,cn=accounts,dc=ipa,dc=example
|
||||
diff --git a/ipaserver/plugins/host.py b/ipaserver/plugins/host.py
|
||||
index 3ef510e..b02c8b5 100644
|
||||
--- a/ipaserver/plugins/host.py
|
||||
+++ b/ipaserver/plugins/host.py
|
||||
@@ -409,7 +409,8 @@ class host(LDAPObject):
|
||||
api.env.container_hostgroup,
|
||||
api.env.basedn),
|
||||
],
|
||||
- 'ipapermdefaultattr': {'krblastpwdchange', 'krbprincipalkey'},
|
||||
+ 'ipapermdefaultattr': {'krblastpwdchange', 'krbprincipalkey',
|
||||
+ 'ipaprotectedoperation;write_keys'},
|
||||
'replaces': [
|
||||
'(targetattr = "krbprincipalkey || krblastpwdchange")(target = "ldap:///fqdn=*,cn=computers,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Manage host keytab";allow (write) groupdn = "ldap:///cn=Manage host keytab,cn=permissions,cn=pbac,$SUFFIX";)',
|
||||
],
|
||||
diff --git a/ipatests/test_integration/test_user_permissions.py b/ipatests/test_integration/test_user_permissions.py
|
||||
index 3333a4f..cd1096f 100644
|
||||
--- a/ipatests/test_integration/test_user_permissions.py
|
||||
+++ b/ipatests/test_integration/test_user_permissions.py
|
||||
@@ -277,6 +277,9 @@ class TestInstallClientNoAdmin(IntegrationTest):
|
||||
self.master.run_command(['ipa', 'privilege-add-permission',
|
||||
'--permissions', 'System: Add Hosts',
|
||||
'Add Hosts'])
|
||||
+ self.master.run_command(['ipa', 'privilege-add-permission',
|
||||
+ '--permissions', 'System: Manage Host Keytab',
|
||||
+ 'Add Hosts'])
|
||||
|
||||
self.master.run_command(['ipa', 'role-add-privilege', 'useradmin',
|
||||
'--privileges', 'Host Enrollment'])
|
||||
@@ -301,6 +304,10 @@ class TestInstallClientNoAdmin(IntegrationTest):
|
||||
encoding='utf-8')
|
||||
assert msg in install_log
|
||||
|
||||
+ # Make sure we do not fallback to an old keytab retrieval method anymore
|
||||
+ msg = "Retrying with pre-4.0 keytab retrieval method..."
|
||||
+ assert msg not in install_log
|
||||
+
|
||||
# check that user is able to request a host cert, too
|
||||
result = tasks.run_certutil(client, ['-L'], paths.IPA_NSSDB_DIR)
|
||||
assert 'Local IPA host' in result.stdout_text
|
||||
|
@ -0,0 +1,36 @@
|
||||
From 4fef80aeaaf017b286bd12ebfc30529f6a65a80e Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Mon, 2 Sep 2024 18:28:27 +0200
|
||||
Subject: [PATCH] ipatests: Add missing comma in
|
||||
test_idrange_no_rid_bases_reversed
|
||||
|
||||
The test is calling ipa idrange-add but is missing a comma in
|
||||
the arguments list.
|
||||
The resulting call is using "--rid-base 100300000--secondary-rid-base".
|
||||
Add the missing comma to build the command with
|
||||
"--rid-base 100300000 --secondary-rid-base"
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9656
|
||||
|
||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
---
|
||||
ipatests/test_integration/test_ipa_idrange_fix.py | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ipatests/test_integration/test_ipa_idrange_fix.py b/ipatests/test_integration/test_ipa_idrange_fix.py
|
||||
index de3da9bfd221ce74f1d1bbb0dbe12e4db08b8daa..ff8fbdac9d028d26fc55f5e357f89af879a61723 100644
|
||||
--- a/ipatests/test_integration/test_ipa_idrange_fix.py
|
||||
+++ b/ipatests/test_integration/test_ipa_idrange_fix.py
|
||||
@@ -72,7 +72,7 @@ class TestIpaIdrangeFix(IntegrationTest):
|
||||
"idrange_reversed",
|
||||
"--base-id", '50000',
|
||||
"--range-size", '20000',
|
||||
- "--rid-base", '100300000'
|
||||
+ "--rid-base", '100300000',
|
||||
"--secondary-rid-base", '301000'
|
||||
])
|
||||
|
||||
--
|
||||
2.46.2
|
||||
|
@ -1,32 +0,0 @@
|
||||
From 2f17319df6147832dceff7c06154363f8d58b194 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Jan 18 2024 09:07:31 +0000
|
||||
Subject: adtrustinstance: make sure NetBIOS name defaults are set properly
|
||||
|
||||
|
||||
Some tools may pass None as NetBIOS name if not put explicitly by a
|
||||
user. This meant to use default NetBIOS name generator based on the
|
||||
domain (realm) name. However, this wasn't done properly, so None is
|
||||
passed later to python-ldap and it rejects such LDAP entry.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9514
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py
|
||||
index bf0cc3b..bb5b61a 100644
|
||||
--- a/ipaserver/install/adtrustinstance.py
|
||||
+++ b/ipaserver/install/adtrustinstance.py
|
||||
@@ -189,6 +189,8 @@ class ADTRUSTInstance(service.Service):
|
||||
self.fqdn = self.fqdn or api.env.host
|
||||
self.host_netbios_name = make_netbios_name(self.fqdn)
|
||||
self.realm = self.realm or api.env.realm
|
||||
+ if not self.netbios_name:
|
||||
+ self.netbios_name = make_netbios_name(self.realm)
|
||||
|
||||
self.suffix = ipautil.realm_to_suffix(self.realm)
|
||||
self.ldapi_socket = "%%2fvar%%2frun%%2fslapd-%s.socket" % \
|
||||
|
32
SOURCES/0007-ipatests-Update-ipa-adtrust-install-test.patch
Normal file
32
SOURCES/0007-ipatests-Update-ipa-adtrust-install-test.patch
Normal file
@ -0,0 +1,32 @@
|
||||
From a18eb8358675b3697ccf8f8d8dc230cc62df6a4d Mon Sep 17 00:00:00 2001
|
||||
From: Erik Belko <ebelko@redhat.com>
|
||||
Date: Thu, 29 Aug 2024 16:47:21 +0200
|
||||
Subject: [PATCH] ipatests: Update ipa-adtrust-install test
|
||||
|
||||
update test_user_connects_smb_share_if_locked_specific_group with wait
|
||||
for SSSD to be online after ipa-adtrust-install command
|
||||
|
||||
Related: https://pagure.io/freeipa/issue/9655
|
||||
|
||||
Signed-off-by: Erik Belko <ebelko@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
---
|
||||
ipatests/test_integration/test_adtrust_install.py | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/ipatests/test_integration/test_adtrust_install.py b/ipatests/test_integration/test_adtrust_install.py
|
||||
index 72e8d874fb17adadc556ba55b825a88a3ac21a67..de252db1705ad940c3b5ee4df967d7c17a4203a7 100644
|
||||
--- a/ipatests/test_integration/test_adtrust_install.py
|
||||
+++ b/ipatests/test_integration/test_adtrust_install.py
|
||||
@@ -853,6 +853,8 @@ class TestIpaAdTrustInstall(IntegrationTest):
|
||||
self.master.config.admin_password,
|
||||
"-U"]
|
||||
)
|
||||
+ # Wait for SSSD to become online before doing any other check
|
||||
+ tasks.wait_for_sssd_domain_status_online(self.master)
|
||||
self.master.run_command(["mkdir", "/freeipa4234"])
|
||||
self.master.run_command(
|
||||
["chcon", "-t", "samba_share_t",
|
||||
--
|
||||
2.46.2
|
||||
|
@ -0,0 +1,33 @@
|
||||
From 373d41f211c1a04dc432a068bc7d2ba825ff554c Mon Sep 17 00:00:00 2001
|
||||
From: Francisco Trivino <ftrivino@redhat.com>
|
||||
Date: Tue, 13 Aug 2024 12:44:21 +0200
|
||||
Subject: [PATCH] Installer: activate ssh service in sssd.conf
|
||||
|
||||
This commit enables SSSD's ssh service in ipa-client-install to ensure
|
||||
sss_ssh_knownhosts and sss_ssh_knownhostsproxy functions properly.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9649
|
||||
Related: https://pagure.io/freeipa/issue/9536
|
||||
|
||||
Signed-off-by: Francisco Trivino <ftrivino@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipaclient/install/client.py | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py
|
||||
index 802db9614b24553b2b49259f3aebb366093560ac..47a371f629f6ddfb1cd5e9fff9faad737aa01f54 100644
|
||||
--- a/ipaclient/install/client.py
|
||||
+++ b/ipaclient/install/client.py
|
||||
@@ -974,6 +974,8 @@ def configure_sssd_conf(
|
||||
|
||||
sssd_enable_service(sssdconfig, 'nss')
|
||||
sssd_enable_service(sssdconfig, 'pam')
|
||||
+ if options.conf_ssh:
|
||||
+ sssd_enable_service(sssdconfig, 'ssh')
|
||||
|
||||
domain.set_option('ipa_domain', cli_domain)
|
||||
domain.set_option('ipa_hostname', client_hostname)
|
||||
--
|
||||
2.46.2
|
||||
|
@ -1,175 +0,0 @@
|
||||
From 5afda72afc6fd626359411b55f092989fdd7d82d Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Jan 15 2024 13:39:21 +0000
|
||||
Subject: ipatests: ignore nsslapd-accesslog-logbuffering WARN in healthcheck
|
||||
|
||||
|
||||
Log buffering is disabled in the integration tests so we can have all
|
||||
the logs at the end. This is causing a warning to show in the 389-ds
|
||||
checks and causing tests to fail that expect all SUCCESS.
|
||||
|
||||
Add an exclude for this specific key so tests will pass again.
|
||||
|
||||
We may eventually want a more sophisiticated mechanism to handle
|
||||
excludes, or updating the config in general, but this is fine for now.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9400
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
|
||||
Reviewed-By: Michal Polovka <mpolovka@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
|
||||
Reviewed-By: Michal Polovka <mpolovka@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py
|
||||
index 7fb8e40..14fba26 100644
|
||||
--- a/ipatests/test_integration/test_ipahealthcheck.py
|
||||
+++ b/ipatests/test_integration/test_ipahealthcheck.py
|
||||
@@ -9,6 +9,7 @@ from __future__ import absolute_import
|
||||
|
||||
from configparser import RawConfigParser, NoOptionError
|
||||
from datetime import datetime, timedelta
|
||||
+import io
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
@@ -208,6 +209,28 @@ def run_healthcheck(host, source=None, check=None, output_type="json",
|
||||
return result.returncode, data
|
||||
|
||||
|
||||
+def set_excludes(host, option, value,
|
||||
+ config_file='/etc/ipahealthcheck/ipahealthcheck.conf'):
|
||||
+ """Mark checks that should be excluded from the results
|
||||
+
|
||||
+ This will set in the [excludes] section on host:
|
||||
+ option=value
|
||||
+ """
|
||||
+ EXCLUDES = "excludes"
|
||||
+
|
||||
+ conf = host.get_file_contents(config_file, encoding='utf-8')
|
||||
+ cfg = RawConfigParser()
|
||||
+ cfg.read_string(conf)
|
||||
+ if not cfg.has_section(EXCLUDES):
|
||||
+ cfg.add_section(EXCLUDES)
|
||||
+ if not cfg.has_option(EXCLUDES, option):
|
||||
+ cfg.set(EXCLUDES, option, value)
|
||||
+ out = io.StringIO()
|
||||
+ cfg.write(out)
|
||||
+ out.seek(0)
|
||||
+ host.put_file_contents(config_file, out.read())
|
||||
+
|
||||
+
|
||||
@pytest.fixture
|
||||
def restart_service():
|
||||
"""Shut down and restart a service as a fixture"""
|
||||
@@ -265,6 +288,7 @@ class TestIpaHealthCheck(IntegrationTest):
|
||||
setup_dns=True,
|
||||
extra_args=['--no-dnssec-validation']
|
||||
)
|
||||
+ set_excludes(cls.master, "key", "DSCLE0004")
|
||||
|
||||
def test_ipa_healthcheck_install_on_master(self):
|
||||
"""
|
||||
@@ -552,6 +576,7 @@ class TestIpaHealthCheck(IntegrationTest):
|
||||
setup_dns=True,
|
||||
extra_args=['--no-dnssec-validation']
|
||||
)
|
||||
+ set_excludes(self.replicas[0], "key", "DSCLE0004")
|
||||
|
||||
# Init a user on replica to assign a DNA range
|
||||
tasks.kinit_admin(self.replicas[0])
|
||||
@@ -692,6 +717,7 @@ class TestIpaHealthCheck(IntegrationTest):
|
||||
'output_type=human'
|
||||
])
|
||||
)
|
||||
+ set_excludes(self.master, "key", "DSCLE0004", config_file)
|
||||
returncode, output = run_healthcheck(
|
||||
self.master, failures_only=True, config=config_file
|
||||
)
|
||||
@@ -707,6 +733,7 @@ class TestIpaHealthCheck(IntegrationTest):
|
||||
'output_file=%s' % HC_LOG,
|
||||
])
|
||||
)
|
||||
+ set_excludes(self.master, "key", "DSCLE0004")
|
||||
returncode, _unused = run_healthcheck(
|
||||
self.master, config=config_file
|
||||
)
|
||||
@@ -2396,6 +2423,7 @@ class TestIpaHealthCLI(IntegrationTest):
|
||||
cls.master, setup_dns=True, extra_args=['--no-dnssec-validation']
|
||||
)
|
||||
tasks.install_packages(cls.master, HEALTHCHECK_PKG)
|
||||
+ set_excludes(cls.master, "key", "DSCLE0004")
|
||||
|
||||
def test_indent(self):
|
||||
"""
|
||||
diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py
|
||||
index d477c3a..b71f2d5 100644
|
||||
--- a/ipatests/test_integration/test_replica_promotion.py
|
||||
+++ b/ipatests/test_integration/test_replica_promotion.py
|
||||
@@ -13,7 +13,7 @@ import pytest
|
||||
|
||||
from ipatests.test_integration.base import IntegrationTest
|
||||
from ipatests.test_integration.test_ipahealthcheck import (
|
||||
- run_healthcheck, HEALTHCHECK_PKG
|
||||
+ run_healthcheck, set_excludes, HEALTHCHECK_PKG
|
||||
)
|
||||
from ipatests.pytest_ipa.integration import tasks
|
||||
from ipatests.pytest_ipa.integration.tasks import (
|
||||
@@ -983,6 +983,9 @@ class TestHiddenReplicaPromotion(IntegrationTest):
|
||||
# manually install KRA to verify that hidden state is synced
|
||||
tasks.install_kra(cls.replicas[0])
|
||||
|
||||
+ set_excludes(cls.master, "key", "DSCLE0004")
|
||||
+ set_excludes(cls.replicas[0], "key", "DSCLE0004")
|
||||
+
|
||||
def _check_dnsrecords(self, hosts_expected, hosts_unexpected=()):
|
||||
domain = DNSName(self.master.domain.name).make_absolute()
|
||||
rset = [
|
||||
|
||||
From f1cfe7d9ff2489dbb6cad70999b0e1bd433c0537 Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Jan 15 2024 13:39:21 +0000
|
||||
Subject: ipatests: fix expected output for ipahealthcheck.ipa.host
|
||||
|
||||
|
||||
ipa-healthcheck commit e69589d5 changed the output when a service
|
||||
keytab is missing to not report the GSSAPI error but to report
|
||||
that the keytab doesn't exist at all. This distinguishes from real
|
||||
Kerberos issues like kvno.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9482
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
|
||||
Reviewed-By: Michal Polovka <mpolovka@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
|
||||
Reviewed-By: Michal Polovka <mpolovka@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py
|
||||
index 14fba26..8aae9fa 100644
|
||||
--- a/ipatests/test_integration/test_ipahealthcheck.py
|
||||
+++ b/ipatests/test_integration/test_ipahealthcheck.py
|
||||
@@ -629,9 +629,15 @@ class TestIpaHealthCheck(IntegrationTest):
|
||||
ipahealthcheck.ipa.host when GSSAPI credentials cannot be obtained
|
||||
from host's keytab.
|
||||
"""
|
||||
- msg = (
|
||||
- "Minor (2529639107): No credentials cache found"
|
||||
- )
|
||||
+ version = tasks.get_healthcheck_version(self.master)
|
||||
+ if parse_version(version) >= parse_version("0.15"):
|
||||
+ msg = (
|
||||
+ "Service {service} keytab {path} does not exist."
|
||||
+ )
|
||||
+ else:
|
||||
+ msg = (
|
||||
+ "Minor (2529639107): No credentials cache found"
|
||||
+ )
|
||||
|
||||
with tasks.FileBackup(self.master, paths.KRB5_KEYTAB):
|
||||
self.master.run_command(["rm", "-f", paths.KRB5_KEYTAB])
|
||||
|
@ -0,0 +1,413 @@
|
||||
From 8d242ba741ec22b258d5e70a530cefd0940783c7 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Tue, 23 Jul 2024 17:07:06 -0400
|
||||
Subject: [PATCH] ipa-migrate - fix migration issues with entries using
|
||||
ipaUniqueId in the RDN
|
||||
|
||||
We need to handle these entries differently and specify what attribute
|
||||
and search base to use to find the entry on the local server. Most
|
||||
entries can use the "cn" attribute but for selinux usermaps we need to
|
||||
search using the ipaOwner attribute which is a DN, and in turn requires
|
||||
additional handling/converting in order to properly check if the usermap
|
||||
exists or not.
|
||||
|
||||
Also fixed an issue where an attribute should be removed from the local
|
||||
entry if it does not exist on the remote entry.
|
||||
|
||||
And fixed the handling od "sudoOrder" which is defined as multi-valued
|
||||
in the schema, but we really need to treat it as single-valued
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9640
|
||||
|
||||
Signed-off-by: Mark Reynolds <mreynolds@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipaserver/install/ipa_migrate.py | 119 +++++++++++++++++++--
|
||||
ipaserver/install/ipa_migrate_constants.py | 84 +++++++++++++--
|
||||
2 files changed, 188 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/ipaserver/install/ipa_migrate.py b/ipaserver/install/ipa_migrate.py
|
||||
index e21937401b3463335d8297b41a403405071d3795..78c530f24fe5d8c9f5de0f816df9904bf30c7b94 100644
|
||||
--- a/ipaserver/install/ipa_migrate.py
|
||||
+++ b/ipaserver/install/ipa_migrate.py
|
||||
@@ -32,7 +32,7 @@ from ipaserver.install.ipa_migrate_constants import (
|
||||
DS_CONFIG, DB_OBJECTS, DS_INDEXES, BIND_DN, LOG_FILE_NAME,
|
||||
STRIP_OP_ATTRS, STRIP_ATTRS, STRIP_OC, PROD_ATTRS,
|
||||
DNA_REGEN_VAL, DNA_REGEN_ATTRS, NIS_PLUGIN, IGNORE_ATTRS,
|
||||
- DB_EXCLUDE_TREES
|
||||
+ DB_EXCLUDE_TREES, POLICY_OP_ATTRS
|
||||
)
|
||||
|
||||
"""
|
||||
@@ -529,6 +529,14 @@ class IPAMigrate():
|
||||
#
|
||||
# Helper functions
|
||||
#
|
||||
+ def attr_is_operational(self, attr):
|
||||
+ schema = self.local_conn.schema
|
||||
+ attr_obj = schema.get_obj(ldap.schema.AttributeType, attr)
|
||||
+ if attr_obj is not None:
|
||||
+ if attr_obj.usage == 1:
|
||||
+ return True
|
||||
+ return False
|
||||
+
|
||||
def replace_suffix(self, entry_dn):
|
||||
"""
|
||||
Replace the base DN in an entry DN
|
||||
@@ -1122,6 +1130,18 @@ class IPAMigrate():
|
||||
stats['reset_range'] += 1
|
||||
return entry
|
||||
|
||||
+ def attr_is_required(self, attr, entry):
|
||||
+ """
|
||||
+ Check if an attribute is required in this entry
|
||||
+ """
|
||||
+ entry_oc = entry['objectClass']
|
||||
+ for oc in entry_oc:
|
||||
+ required_attrs = self.local_conn.get_allowed_attributes(
|
||||
+ [oc], raise_on_unknown=False, attributes="must")
|
||||
+ if attr.lower() in required_attrs:
|
||||
+ return True
|
||||
+ return False
|
||||
+
|
||||
def clean_entry(self, entry_dn, entry_type, entry_attrs):
|
||||
"""
|
||||
Clean up the entry from the remote server
|
||||
@@ -1311,7 +1331,17 @@ class IPAMigrate():
|
||||
f"'{old_value}' "
|
||||
"new value "
|
||||
f"'{local_entry[attr][0]}'")
|
||||
-
|
||||
+ elif 'single' == sp_attr[1]:
|
||||
+ # The attribute is defined as multivalued, but
|
||||
+ # we really need to treat it as single valued
|
||||
+ self.log_debug("Entry is different and will "
|
||||
+ f"be updated: '{local_dn}' "
|
||||
+ f"attribute '{attr}' replaced "
|
||||
+ "with val "
|
||||
+ f"'{remote_attrs[attr][0]}' "
|
||||
+ "old value: "
|
||||
+ f"{local_entry[attr][0]}")
|
||||
+ local_entry[attr][0] = remote_attrs[attr][0]
|
||||
goto_next_attr = True
|
||||
break
|
||||
|
||||
@@ -1358,6 +1388,31 @@ class IPAMigrate():
|
||||
local_entry[attr] = remote_attrs[attr]
|
||||
entry_updated = True
|
||||
|
||||
+ # Remove attributes in the local entry that do not exist in the
|
||||
+ # remote entry
|
||||
+ remove_attrs = []
|
||||
+ for attr in local_entry:
|
||||
+ if (self.attr_is_operational(attr)
|
||||
+ and attr.lower() not in POLICY_OP_ATTRS) or \
|
||||
+ attr.lower() in IGNORE_ATTRS or \
|
||||
+ attr.lower() in STRIP_ATTRS or \
|
||||
+ attr.lower() == "usercertificate":
|
||||
+ # This is an attribute that we do not want to remove
|
||||
+ continue
|
||||
+
|
||||
+ if attr not in remote_attrs and \
|
||||
+ not self.attr_is_required(attr, local_entry):
|
||||
+ # Mark this attribute for deletion
|
||||
+ remove_attrs.append(attr)
|
||||
+ entry_updated = True
|
||||
+
|
||||
+ # Remove attributes
|
||||
+ for remove_attr in remove_attrs:
|
||||
+ self.log_debug("Entry is different and will be updated: "
|
||||
+ f"'{local_dn}' attribute '{remove_attr}' "
|
||||
+ "is being removed")
|
||||
+ del local_entry[remove_attr]
|
||||
+
|
||||
if range_reset:
|
||||
stats['reset_range'] += 1
|
||||
|
||||
@@ -1371,6 +1426,9 @@ class IPAMigrate():
|
||||
"""
|
||||
Process chunks of remote entries from a paged results search
|
||||
|
||||
+ entry_dn = the remote entry DN
|
||||
+ entry_attrs = the remote entry's attributes stored in a dict
|
||||
+
|
||||
Identify entry type
|
||||
Process entry (removing/change attr/val/schema)
|
||||
Compare processed remote entry with local entry, merge/overwrite?
|
||||
@@ -1426,6 +1484,47 @@ class IPAMigrate():
|
||||
# Based on the entry type do additional work
|
||||
#
|
||||
|
||||
+ # For entries with alternate identifying needs we need to rebuild the
|
||||
+ # local dn. Typically this is for entries that use ipaUniqueId as the
|
||||
+ # RDN attr
|
||||
+ if entry_type != "custom" and 'alt_id' in DB_OBJECTS[entry_type]:
|
||||
+ attr = DB_OBJECTS[entry_type]['alt_id']['attr']
|
||||
+ base = DB_OBJECTS[entry_type]['alt_id']['base']
|
||||
+ srch_filter = f'{attr}={entry_attrs[attr][0]}'
|
||||
+ if DB_OBJECTS[entry_type]['alt_id']['isDN'] is True:
|
||||
+ # Convert the filter to match the local suffix
|
||||
+ srch_filter = self.replace_suffix(srch_filter)
|
||||
+ srch_base = base + str(self.local_suffix)
|
||||
+
|
||||
+ try:
|
||||
+ entries = self.local_conn.get_entries(DN(srch_base),
|
||||
+ filter=srch_filter)
|
||||
+ if len(entries) == 1:
|
||||
+ local_dn = entries[0].dn
|
||||
+ elif len(entries) == 0:
|
||||
+ # Not found, no problem just proceed and we will add it
|
||||
+ pass
|
||||
+ else:
|
||||
+ # Found too many entries - should not happen
|
||||
+ self.log_error('Found too many local matching entries '
|
||||
+ f'for "{local_dn}"')
|
||||
+ if self.args.force:
|
||||
+ stats['ignored_errors'] += 1
|
||||
+ return
|
||||
+ else:
|
||||
+ sys.exit(1)
|
||||
+ except errors.EmptyResult:
|
||||
+ # Not found, no problem just proceed and we will add it later
|
||||
+ pass
|
||||
+ except (errors.NetworkError, errors.DatabaseError) as e:
|
||||
+ self.log_error('Failed to find a local matching entry for '
|
||||
+ f'"{local_dn}" error: {str(e)}')
|
||||
+ if self.args.force:
|
||||
+ stats['ignored_errors'] += 1
|
||||
+ return
|
||||
+ else:
|
||||
+ sys.exit(1)
|
||||
+
|
||||
# See if the entry exists on the local server
|
||||
try:
|
||||
local_entry = self.local_conn.get_entry(DN(local_dn),
|
||||
@@ -1441,14 +1540,20 @@ class IPAMigrate():
|
||||
|
||||
if self.dryrun:
|
||||
self.write_update_to_ldif(local_entry)
|
||||
- DB_OBJECTS[entry_type]['count'] += 1
|
||||
+ if entry_type == "custom":
|
||||
+ stats['custom'] += 1
|
||||
+ else:
|
||||
+ DB_OBJECTS[entry_type]['count'] += 1
|
||||
stats['total_db_migrated'] += 1
|
||||
return
|
||||
|
||||
# Update the local entry
|
||||
try:
|
||||
self.local_conn.update_entry(local_entry)
|
||||
- DB_OBJECTS[entry_type]['count'] += 1
|
||||
+ if entry_type == "custom":
|
||||
+ stats['custom'] += 1
|
||||
+ else:
|
||||
+ DB_OBJECTS[entry_type]['count'] += 1
|
||||
except errors.ExecutionError as e:
|
||||
self.log_error(f'Failed to update "{local_dn}" error: '
|
||||
f'{str(e)}')
|
||||
@@ -1567,7 +1672,7 @@ class IPAMigrate():
|
||||
"""
|
||||
Used paged search for online method to avoid large memory footprint
|
||||
"""
|
||||
- self.log_info("Migrating database ... (this make take a while)")
|
||||
+ self.log_info("Migrating database ... (this may take a while)")
|
||||
if self.args.db_ldif is not None:
|
||||
self.processDBOffline()
|
||||
else:
|
||||
@@ -1608,7 +1713,7 @@ class IPAMigrate():
|
||||
f"{len(objectclasses)} objectClasses")
|
||||
|
||||
# Loop over attributes and objectclasses and count them
|
||||
- schema = self.local_conn._get_schema()
|
||||
+ schema = self.local_conn.schema
|
||||
local_schema = schema.ldap_entry()
|
||||
for schema_type in [(attributes, "attributeTypes"),
|
||||
(objectclasses, "objectClasses")]:
|
||||
@@ -1967,7 +2072,7 @@ class IPAMigrate():
|
||||
|
||||
# Run ipa-server-upgrade
|
||||
self.log_info("Running ipa-server-upgrade ... "
|
||||
- "(this make take a while)")
|
||||
+ "(this may take a while)")
|
||||
if self.dryrun:
|
||||
self.log_info("Skipping ipa-server-upgrade in dryrun mode.")
|
||||
else:
|
||||
diff --git a/ipaserver/install/ipa_migrate_constants.py b/ipaserver/install/ipa_migrate_constants.py
|
||||
index 0e26c75497b216f09ed450aa25a09c2102582326..250f1b5b01bf066d316a98489ab6153b89615173 100644
|
||||
--- a/ipaserver/install/ipa_migrate_constants.py
|
||||
+++ b/ipaserver/install/ipa_migrate_constants.py
|
||||
@@ -19,6 +19,28 @@ STRIP_OP_ATTRS = [
|
||||
'nsuniqueid',
|
||||
'dsentrydn',
|
||||
'entryuuid',
|
||||
+ 'entrydn',
|
||||
+ 'entryid',
|
||||
+ 'entryusn',
|
||||
+ 'numsubordinates',
|
||||
+ 'parentid',
|
||||
+ 'tombstonenumsubordinates'
|
||||
+]
|
||||
+
|
||||
+# Operational attributes that we would want to remove from the local entry if
|
||||
+# they don't exist in the remote entry
|
||||
+POLICY_OP_ATTRS = [
|
||||
+ 'nsaccountlock',
|
||||
+ 'passwordexpiratontime',
|
||||
+ 'passwordgraceusertime',
|
||||
+ 'pwdpolicysubentry',
|
||||
+ 'passwordexpwarned',
|
||||
+ 'passwordretrycount',
|
||||
+ 'retrycountresettime',
|
||||
+ 'accountunlocktime',
|
||||
+ 'passwordhistory',
|
||||
+ 'passwordallowchangetime',
|
||||
+ 'pwdreset'
|
||||
]
|
||||
|
||||
# Atributes to strip from users/groups
|
||||
@@ -110,7 +132,7 @@ STRIP_OC = [
|
||||
#
|
||||
# The DS_CONFIG mapping breaks each config entry (or type of entry) into its
|
||||
# own catagory. Each catagory, or type, as DN list "dn", the attributes# we
|
||||
-# are intrested in. These attributes are broken into singel valued "attrs",
|
||||
+# are intrested in. These attributes are broken into single valued "attrs",
|
||||
# or multi-valued attributes "multivalued". If the attributes is single
|
||||
# valued then the value is replaced, if it's multivalued then it is "appended"
|
||||
#
|
||||
@@ -503,7 +525,7 @@ DS_CONFIG = {
|
||||
}
|
||||
|
||||
#
|
||||
-# Slpai NIS is an optional plugin. It requires special handling
|
||||
+# Slapi NIS is an optional plugin. It requires special handling
|
||||
#
|
||||
NIS_PLUGIN = {
|
||||
'dn': 'cn=NIS Server,cn=plugins,cn=config',
|
||||
@@ -565,6 +587,12 @@ DS_INDEXES = {
|
||||
# identify the entry.
|
||||
# The "label" and "count" attributes are used for the Summary Report
|
||||
#
|
||||
+# Some entries use ipaUniqueId as the RDN attribute, this makes comparing
|
||||
+# entries between the remote and local servers problematic. So we need special
|
||||
+# identifying information to find the local entry. In this case we use the
|
||||
+# "alt_id" key which is a dict of an attribute 'attr' and partial base DN
|
||||
+# 'base' - which is expected to end in a comma.
|
||||
+#
|
||||
DB_OBJECTS = {
|
||||
# Plugins
|
||||
'automember_def': {
|
||||
@@ -640,8 +668,8 @@ DB_OBJECTS = {
|
||||
'oc': ['ipaconfigobject', 'ipaguiconfig'],
|
||||
'subtree': 'cn=ipaconfig,cn=etc,$SUFFIX',
|
||||
'special_attrs': [
|
||||
- # needs special handling, but
|
||||
- # ipa-server-upgrade rewrites this attribute anyway!
|
||||
+ # needs special handling, but ipa-server-upgrade rewrites this
|
||||
+ # attribute anyway!
|
||||
('ipausersearchfields', 'list'),
|
||||
],
|
||||
'label': 'IPA Config',
|
||||
@@ -772,11 +800,16 @@ DB_OBJECTS = {
|
||||
'mode': 'all',
|
||||
'count': 0,
|
||||
},
|
||||
- 'subids': { # unknown what these entries look like TODO
|
||||
+ 'subids': {
|
||||
'oc': [],
|
||||
'subtree': ',cn=subids,cn=accounts,$SUFFIX',
|
||||
'label': 'Sub IDs',
|
||||
- 'mode': 'all', # TODO Maybe production only?
|
||||
+ 'mode': 'production',
|
||||
+ 'alt_id': {
|
||||
+ 'attr': 'ipaOwner',
|
||||
+ 'isDN': True,
|
||||
+ 'base': 'cn=subids,cn=accounts,',
|
||||
+ },
|
||||
'count': 0,
|
||||
},
|
||||
|
||||
@@ -884,6 +917,11 @@ DB_OBJECTS = {
|
||||
'oc': ['ipahbacrule'],
|
||||
'subtree': ',cn=hbac,$SUFFIX',
|
||||
'label': 'HBAC Rules',
|
||||
+ 'alt_id': {
|
||||
+ 'attr': 'cn',
|
||||
+ 'base': 'cn=hbac,',
|
||||
+ 'isDN': False,
|
||||
+ },
|
||||
'mode': 'all',
|
||||
'count': 0,
|
||||
},
|
||||
@@ -892,6 +930,11 @@ DB_OBJECTS = {
|
||||
'selinux_usermap': { # Not sure if this is needed, entry is empty TODO
|
||||
'oc': [],
|
||||
'subtree': ',cn=usermap,cn=selinux,$SUFFIX',
|
||||
+ 'alt_id': {
|
||||
+ 'attr': 'cn',
|
||||
+ 'base': 'cn=usermap,cn=selinux,',
|
||||
+ 'isDN': False,
|
||||
+ },
|
||||
'label': 'Selinux Usermaps',
|
||||
'mode': 'all',
|
||||
'count': 0,
|
||||
@@ -902,12 +945,27 @@ DB_OBJECTS = {
|
||||
'oc': ['ipasudorule'],
|
||||
'subtree': ',cn=sudorules,cn=sudo,$SUFFIX',
|
||||
'label': 'Sudo Rules',
|
||||
+ 'alt_id': {
|
||||
+ 'attr': 'cn',
|
||||
+ 'base': 'cn=sudorules,cn=sudo,',
|
||||
+ 'isDN': False,
|
||||
+ },
|
||||
+ 'special_attrs': [
|
||||
+ # schema defines sudoOrder as mutlivalued, but we need to treat
|
||||
+ # it as single valued
|
||||
+ ('sudoorder', 'single'),
|
||||
+ ],
|
||||
'mode': 'all',
|
||||
'count': 0,
|
||||
},
|
||||
'sudo_cmds': {
|
||||
'oc': ['ipasudocmd'],
|
||||
'subtree': ',cn=sudocmds,cn=sudo,$SUFFIX',
|
||||
+ 'alt_id': {
|
||||
+ 'attr': 'sudoCmd',
|
||||
+ 'base': 'cn=sudocmds,cn=sudo,',
|
||||
+ 'isDN': False,
|
||||
+ },
|
||||
'label': 'Sudo Commands',
|
||||
'mode': 'all',
|
||||
'count': 0,
|
||||
@@ -991,6 +1049,11 @@ DB_OBJECTS = {
|
||||
'oc': ['ipanisnetgroup'],
|
||||
'not_oc': ['mepmanagedentry'],
|
||||
'subtree': ',cn=ng,cn=alt,$SUFFIX',
|
||||
+ 'alt_id': {
|
||||
+ 'attr': 'cn',
|
||||
+ 'base': 'cn=ng,cn=alt,',
|
||||
+ 'isDN': False,
|
||||
+ },
|
||||
'label': 'Network Groups',
|
||||
'mode': 'all',
|
||||
'count': 0,
|
||||
@@ -1006,9 +1069,14 @@ DB_OBJECTS = {
|
||||
'count': 0,
|
||||
},
|
||||
'caacls': {
|
||||
- 'oc': ['top'],
|
||||
+ 'oc': ['ipacaacl'],
|
||||
'subtree': ',cn=caacls,cn=ca,$SUFFIX',
|
||||
- 'label': 'CA Certificates',
|
||||
+ 'alt_id': {
|
||||
+ 'attr': 'cn',
|
||||
+ 'base': 'cn=caacls,cn=ca,',
|
||||
+ 'isDN': False,
|
||||
+ },
|
||||
+ 'label': 'CA Certificate ACLs',
|
||||
'mode': 'all',
|
||||
'count': 0,
|
||||
},
|
||||
--
|
||||
2.46.2
|
||||
|
@ -1,45 +0,0 @@
|
||||
From dcb9d6edc7ae4278cd552e87f644705faa13d558 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Jan 31 2024 08:31:13 +0000
|
||||
Subject: kdb: PAC generator: do not fail if canonical principal is missing
|
||||
|
||||
|
||||
krbCanonicalName is mandatory for services but IPA services created
|
||||
before commit e6ff83e (FreeIPA 4.4.0, ~2016) had no normalization done
|
||||
to set krbCanonicalName; services created after that version were
|
||||
upgraded to do have krbCanonicalName.
|
||||
|
||||
Accept krbPrincipalName alone since they have no alias either */
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9465
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Thierry Bordaz <tbordaz@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
index 9e1431c..8035036 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
@@ -496,8 +496,16 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
|
||||
ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
|
||||
"krbCanonicalName", &strres);
|
||||
if (ret) {
|
||||
- /* krbCanonicalName is mandatory for services */
|
||||
- return ret;
|
||||
+ /* krbCanonicalName is mandatory for services but IPA services
|
||||
+ * created before commit e6ff83e (FreeIPA 4.4.0, ~2016) had no
|
||||
+ * normalization to set krbCanonicalName; services created after
|
||||
+ * that version were upgraded to do have krbCanonicalName.
|
||||
+ *
|
||||
+ * Accept krbPrincipalName alone since they have no alias either */
|
||||
+ ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
|
||||
+ "krbPrincipalName", &strres);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
ret = krb5_parse_name(ipactx->kcontext, strres, &princ);
|
||||
|
@ -1,89 +0,0 @@
|
||||
From bac601b7f35827236a106f7137f378e4888260da Mon Sep 17 00:00:00 2001
|
||||
From: Julien Rische <jrische@redhat.com>
|
||||
Date: Jan 30 2024 15:17:44 +0000
|
||||
Subject: ipa-kdb: Fix memory leak during PAC verification
|
||||
|
||||
|
||||
Commit 0022bd70d93708d325855d5271516d6cd894d6e8 introduced a memory leak
|
||||
during the copy of some PAC buffers, because of an unfreed memory
|
||||
allocation context.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9520
|
||||
|
||||
Signed-off-by: Julien Rische <jrische@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
index a18beff..9e1431c 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
@@ -2316,6 +2316,7 @@ krb5_error_code ipadb_common_verify_pac(krb5_context context,
|
||||
size_t i;
|
||||
struct dom_sid *requester_sid = NULL;
|
||||
struct dom_sid req_sid;
|
||||
+ TALLOC_CTX *tmpctx = NULL;
|
||||
|
||||
if (signing_krbtgt != NULL &&
|
||||
ipadb_is_cross_realm_krbtgt(signing_krbtgt->princ)) {
|
||||
@@ -2371,6 +2372,12 @@ krb5_error_code ipadb_common_verify_pac(krb5_context context,
|
||||
goto done;
|
||||
}
|
||||
|
||||
+ tmpctx = talloc_new(NULL);
|
||||
+ if (tmpctx == NULL) {
|
||||
+ kerr = ENOMEM;
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
for (i = 0; i < num_buffers; i++) {
|
||||
if (types[i] == KRB5_PAC_SERVER_CHECKSUM ||
|
||||
types[i] == KRB5_PAC_PRIVSVR_CHECKSUM ||
|
||||
@@ -2395,32 +2402,21 @@ krb5_error_code ipadb_common_verify_pac(krb5_context context,
|
||||
DATA_BLOB pac_attrs_data;
|
||||
krb5_boolean pac_requested;
|
||||
|
||||
- TALLOC_CTX *tmpctx = talloc_new(NULL);
|
||||
- if (tmpctx == NULL) {
|
||||
- kerr = ENOMEM;
|
||||
- goto done;
|
||||
- }
|
||||
-
|
||||
kerr = ipadb_client_requested_pac(context, old_pac, tmpctx, &pac_requested);
|
||||
- if (kerr != 0) {
|
||||
- talloc_free(tmpctx);
|
||||
+ if (kerr)
|
||||
goto done;
|
||||
- }
|
||||
|
||||
kerr = ipadb_get_pac_attrs_blob(tmpctx, &pac_requested, &pac_attrs_data);
|
||||
- if (kerr) {
|
||||
- talloc_free(tmpctx);
|
||||
+ if (kerr)
|
||||
goto done;
|
||||
- }
|
||||
+
|
||||
data.magic = KV5M_DATA;
|
||||
data.data = (char *)pac_attrs_data.data;
|
||||
data.length = pac_attrs_data.length;
|
||||
|
||||
kerr = krb5_pac_add_buffer(context, new_pac, PAC_TYPE_ATTRIBUTES_INFO, &data);
|
||||
- if (kerr) {
|
||||
- talloc_free(tmpctx);
|
||||
+ if (kerr)
|
||||
goto done;
|
||||
- }
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -2467,6 +2463,8 @@ done:
|
||||
if (kerr != 0 && (new_pac != *pac)) {
|
||||
krb5_pac_free(context, new_pac);
|
||||
}
|
||||
+ if (tmpctx)
|
||||
+ talloc_free(tmpctx);
|
||||
krb5_free_data_contents(context, &pac_blob);
|
||||
free(types);
|
||||
return kerr;
|
||||
|
@ -0,0 +1,68 @@
|
||||
From 3b5a980f5b65b03b9fd7ad0cfbb6c87874d3ff24 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Tue, 3 Sep 2024 13:42:05 -0400
|
||||
Subject: [PATCH] ipa-migrate - fix alternate entry search filter
|
||||
|
||||
Processing a filter like a DN can cause normalization issues that result
|
||||
in an invalid filter. Make sure the filter is encapsulated with
|
||||
parenthesis and we call replace_suffix_value() instead of
|
||||
replace_suffix()
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9658
|
||||
|
||||
Signed-off-by: Mark Reynolds <mreynolds@redhat.com>
|
||||
|
||||
Fix typo in test
|
||||
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
---
|
||||
ipaserver/install/ipa_migrate.py | 4 ++--
|
||||
ipatests/test_integration/test_ipa_ipa_migration.py | 6 +++---
|
||||
2 files changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/ipaserver/install/ipa_migrate.py b/ipaserver/install/ipa_migrate.py
|
||||
index 78c530f24fe5d8c9f5de0f816df9904bf30c7b94..38356aa23ea435e2a616f48356feaea7b50dd1e4 100644
|
||||
--- a/ipaserver/install/ipa_migrate.py
|
||||
+++ b/ipaserver/install/ipa_migrate.py
|
||||
@@ -1490,10 +1490,10 @@ class IPAMigrate():
|
||||
if entry_type != "custom" and 'alt_id' in DB_OBJECTS[entry_type]:
|
||||
attr = DB_OBJECTS[entry_type]['alt_id']['attr']
|
||||
base = DB_OBJECTS[entry_type]['alt_id']['base']
|
||||
- srch_filter = f'{attr}={entry_attrs[attr][0]}'
|
||||
+ srch_filter = f'({attr}={entry_attrs[attr][0]})'
|
||||
if DB_OBJECTS[entry_type]['alt_id']['isDN'] is True:
|
||||
# Convert the filter to match the local suffix
|
||||
- srch_filter = self.replace_suffix(srch_filter)
|
||||
+ srch_filter = self.replace_suffix_value(srch_filter)
|
||||
srch_base = base + str(self.local_suffix)
|
||||
|
||||
try:
|
||||
diff --git a/ipatests/test_integration/test_ipa_ipa_migration.py b/ipatests/test_integration/test_ipa_ipa_migration.py
|
||||
index f697bbfbfc6169309274db689501c99fe148cc70..288165e8a83a96e6f6bd4e52866f98617f497c56 100644
|
||||
--- a/ipatests/test_integration/test_ipa_ipa_migration.py
|
||||
+++ b/ipatests/test_integration/test_ipa_ipa_migration.py
|
||||
@@ -610,7 +610,7 @@ class TestIPAMigrateScenario1(IntegrationTest):
|
||||
MIGRATION_SCHEMA_LOG_MSG = "Migrating schema ...\n"
|
||||
MIGRATION_CONFIG_LOG_MSG = "Migrating configuration ...\n"
|
||||
IPA_UPGRADE_LOG_MSG = (
|
||||
- "Running ipa-server-upgrade ... (this make take a while)\n"
|
||||
+ "Running ipa-server-upgrade ... (this may take a while)\n"
|
||||
)
|
||||
SIDGEN_TASK_LOG_MSG = "Running SIDGEN task ...\n"
|
||||
MIGRATION_COMPLETE_LOG_MSG = "Migration complete!\n"
|
||||
@@ -641,10 +641,10 @@ class TestIPAMigrateScenario1(IntegrationTest):
|
||||
tasks.kinit_admin(self.replicas[0])
|
||||
MIGRATION_SCHEMA_LOG_MSG = "Migrating schema ...\n"
|
||||
MIGRATION_DATABASE_LOG_MSG = (
|
||||
- "Migrating database ... (this make take a while)\n"
|
||||
+ "Migrating database ... (this may take a while)\n"
|
||||
)
|
||||
IPA_UPGRADE_LOG_MSG = (
|
||||
- "Running ipa-server-upgrade ... (this make take a while)\n"
|
||||
+ "Running ipa-server-upgrade ... (this may take a while)\n"
|
||||
)
|
||||
SIDGEN_TASK_LOG_MSG = "Running SIDGEN task ...\n"
|
||||
result = run_migrate(
|
||||
--
|
||||
2.46.2
|
||||
|
@ -1,238 +0,0 @@
|
||||
From 381af470779ea87335f57038dcbe72cd042ae6bb Mon Sep 17 00:00:00 2001
|
||||
From: Stanislav Levin <slev@altlinux.org>
|
||||
Date: Jan 30 2024 15:11:05 +0000
|
||||
Subject: ipapython: Clean up krb5_error
|
||||
|
||||
|
||||
`krb5_error` has different definition in MIT krb.
|
||||
https://web.mit.edu/kerberos/krb5-latest/doc/appdev/refs/types/krb5_error.html
|
||||
|
||||
> Error message structure.
|
||||
>
|
||||
> Declaration:
|
||||
> typedef struct _krb5_error krb5_error
|
||||
|
||||
While `krb5_error_code`
|
||||
https://web.mit.edu/kerberos/www/krb5-latest/doc/appdev/refs/types/krb5_error_code.html#c.krb5_error_code
|
||||
|
||||
> krb5_error_code
|
||||
> Used to convey an operation status.
|
||||
>
|
||||
> The value 0 indicates success; any other values are com_err codes. Use krb5_get_error_message() to obtain a string describing the error.
|
||||
>
|
||||
> Declaration
|
||||
> typedef krb5_int32 krb5_error_code
|
||||
|
||||
And this is what was actually used.
|
||||
|
||||
To prevent confusion of types `krb5_error` was replaced with
|
||||
`krb5_error_code`.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9519
|
||||
Signed-off-by: Stanislav Levin <slev@altlinux.org>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/ipapython/session_storage.py b/ipapython/session_storage.py
|
||||
index c43ef7d..371cf15 100644
|
||||
--- a/ipapython/session_storage.py
|
||||
+++ b/ipapython/session_storage.py
|
||||
@@ -111,7 +111,7 @@ class KRB5Error(Exception):
|
||||
|
||||
|
||||
def krb5_errcheck(result, func, arguments):
|
||||
- """Error checker for krb5_error return value"""
|
||||
+ """Error checker for krb5_error_code return value"""
|
||||
if result != 0:
|
||||
raise KRB5Error(result, func.__name__, arguments)
|
||||
|
||||
@@ -119,14 +119,13 @@ def krb5_errcheck(result, func, arguments):
|
||||
krb5_context = ctypes.POINTER(_krb5_context)
|
||||
krb5_ccache = ctypes.POINTER(_krb5_ccache)
|
||||
krb5_data_p = ctypes.POINTER(_krb5_data)
|
||||
-krb5_error = ctypes.c_int32
|
||||
krb5_creds = _krb5_creds
|
||||
krb5_pointer = ctypes.c_void_p
|
||||
krb5_cc_cursor = krb5_pointer
|
||||
|
||||
krb5_init_context = LIBKRB5.krb5_init_context
|
||||
krb5_init_context.argtypes = (ctypes.POINTER(krb5_context), )
|
||||
-krb5_init_context.restype = krb5_error
|
||||
+krb5_init_context.restype = krb5_error_code
|
||||
krb5_init_context.errcheck = krb5_errcheck
|
||||
|
||||
krb5_free_context = LIBKRB5.krb5_free_context
|
||||
@@ -143,30 +142,30 @@ krb5_free_data_contents.restype = None
|
||||
|
||||
krb5_cc_default = LIBKRB5.krb5_cc_default
|
||||
krb5_cc_default.argtypes = (krb5_context, ctypes.POINTER(krb5_ccache), )
|
||||
-krb5_cc_default.restype = krb5_error
|
||||
+krb5_cc_default.restype = krb5_error_code
|
||||
krb5_cc_default.errcheck = krb5_errcheck
|
||||
|
||||
krb5_cc_close = LIBKRB5.krb5_cc_close
|
||||
krb5_cc_close.argtypes = (krb5_context, krb5_ccache, )
|
||||
-krb5_cc_close.restype = krb5_error
|
||||
+krb5_cc_close.restype = krb5_error_code
|
||||
krb5_cc_close.errcheck = krb5_errcheck
|
||||
|
||||
krb5_parse_name = LIBKRB5.krb5_parse_name
|
||||
krb5_parse_name.argtypes = (krb5_context, ctypes.c_char_p,
|
||||
ctypes.POINTER(krb5_principal), )
|
||||
-krb5_parse_name.restype = krb5_error
|
||||
+krb5_parse_name.restype = krb5_error_code
|
||||
krb5_parse_name.errcheck = krb5_errcheck
|
||||
|
||||
krb5_cc_set_config = LIBKRB5.krb5_cc_set_config
|
||||
krb5_cc_set_config.argtypes = (krb5_context, krb5_ccache, krb5_principal,
|
||||
ctypes.c_char_p, krb5_data_p, )
|
||||
-krb5_cc_set_config.restype = krb5_error
|
||||
+krb5_cc_set_config.restype = krb5_error_code
|
||||
krb5_cc_set_config.errcheck = krb5_errcheck
|
||||
|
||||
krb5_cc_get_principal = LIBKRB5.krb5_cc_get_principal
|
||||
krb5_cc_get_principal.argtypes = (krb5_context, krb5_ccache,
|
||||
ctypes.POINTER(krb5_principal), )
|
||||
-krb5_cc_get_principal.restype = krb5_error
|
||||
+krb5_cc_get_principal.restype = krb5_error_code
|
||||
krb5_cc_get_principal.errcheck = krb5_errcheck
|
||||
|
||||
# krb5_build_principal is a variadic function but that can't be expressed
|
||||
@@ -177,26 +176,26 @@ krb5_build_principal.argtypes = (krb5_context, ctypes.POINTER(krb5_principal),
|
||||
ctypes.c_uint, ctypes.c_char_p,
|
||||
ctypes.c_char_p, ctypes.c_char_p,
|
||||
ctypes.c_char_p, ctypes.c_char_p, )
|
||||
-krb5_build_principal.restype = krb5_error
|
||||
+krb5_build_principal.restype = krb5_error_code
|
||||
krb5_build_principal.errcheck = krb5_errcheck
|
||||
|
||||
krb5_cc_start_seq_get = LIBKRB5.krb5_cc_start_seq_get
|
||||
krb5_cc_start_seq_get.argtypes = (krb5_context, krb5_ccache,
|
||||
ctypes.POINTER(krb5_cc_cursor), )
|
||||
-krb5_cc_start_seq_get.restype = krb5_error
|
||||
+krb5_cc_start_seq_get.restype = krb5_error_code
|
||||
krb5_cc_start_seq_get.errcheck = krb5_errcheck
|
||||
|
||||
krb5_cc_next_cred = LIBKRB5.krb5_cc_next_cred
|
||||
krb5_cc_next_cred.argtypes = (krb5_context, krb5_ccache,
|
||||
ctypes.POINTER(krb5_cc_cursor),
|
||||
ctypes.POINTER(krb5_creds), )
|
||||
-krb5_cc_next_cred.restype = krb5_error
|
||||
+krb5_cc_next_cred.restype = krb5_error_code
|
||||
krb5_cc_next_cred.errcheck = krb5_errcheck
|
||||
|
||||
krb5_cc_end_seq_get = LIBKRB5.krb5_cc_end_seq_get
|
||||
krb5_cc_end_seq_get.argtypes = (krb5_context, krb5_ccache,
|
||||
ctypes.POINTER(krb5_cc_cursor), )
|
||||
-krb5_cc_end_seq_get.restype = krb5_error
|
||||
+krb5_cc_end_seq_get.restype = krb5_error_code
|
||||
krb5_cc_end_seq_get.errcheck = krb5_errcheck
|
||||
|
||||
krb5_free_cred_contents = LIBKRB5.krb5_free_cred_contents
|
||||
@@ -212,7 +211,7 @@ krb5_principal_compare.restype = krb5_boolean
|
||||
krb5_unparse_name = LIBKRB5.krb5_unparse_name
|
||||
krb5_unparse_name.argtypes = (krb5_context, krb5_principal,
|
||||
ctypes.POINTER(ctypes.c_char_p), )
|
||||
-krb5_unparse_name.restype = krb5_error
|
||||
+krb5_unparse_name.restype = krb5_error_code
|
||||
krb5_unparse_name.errcheck = krb5_errcheck
|
||||
|
||||
krb5_free_unparsed_name = LIBKRB5.krb5_free_unparsed_name
|
||||
|
||||
From 2a4bad8bb3295c5c0f5a760ecd41871c4c5a0c56 Mon Sep 17 00:00:00 2001
|
||||
From: Stanislav Levin <slev@altlinux.org>
|
||||
Date: Jan 30 2024 15:11:05 +0000
|
||||
Subject: ipapython: Correct return type of krb5_free_cred_contents
|
||||
|
||||
|
||||
According to https://web.mit.edu/kerberos/krb5-latest/doc/appdev/refs/api/krb5_free_cred_contents.html
|
||||
|
||||
> krb5_free_cred_contents - Free the contents of a krb5_creds structure.
|
||||
>
|
||||
> void krb5_free_cred_contents(krb5_context context, krb5_creds * val)
|
||||
> param:
|
||||
> [in] context - Library context
|
||||
>
|
||||
> [in] val - Credential structure to free contents of
|
||||
>
|
||||
> This function frees the contents of val , but not the structure itself.
|
||||
|
||||
https://github.com/krb5/krb5/blob/5b00197227231943bd2305328c8260dd0b0dbcf0/src/lib/krb5/krb/kfree.c#L166
|
||||
|
||||
This leads to undefined behavior and `krb5_free_cred_contents` can
|
||||
raise KRB5Error (because of garbage data) while actually its foreign
|
||||
function doesn't.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9519
|
||||
Signed-off-by: Stanislav Levin <slev@altlinux.org>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/ipapython/session_storage.py b/ipapython/session_storage.py
|
||||
index 371cf15..dc36f54 100644
|
||||
--- a/ipapython/session_storage.py
|
||||
+++ b/ipapython/session_storage.py
|
||||
@@ -200,8 +200,7 @@ krb5_cc_end_seq_get.errcheck = krb5_errcheck
|
||||
|
||||
krb5_free_cred_contents = LIBKRB5.krb5_free_cred_contents
|
||||
krb5_free_cred_contents.argtypes = (krb5_context, ctypes.POINTER(krb5_creds))
|
||||
-krb5_free_cred_contents.restype = krb5_error
|
||||
-krb5_free_cred_contents.errcheck = krb5_errcheck
|
||||
+krb5_free_cred_contents.restype = None
|
||||
|
||||
krb5_principal_compare = LIBKRB5.krb5_principal_compare
|
||||
krb5_principal_compare.argtypes = (krb5_context, krb5_principal,
|
||||
|
||||
From beb402afdbf32c01eed860e9416356f7b492ad74 Mon Sep 17 00:00:00 2001
|
||||
From: Stanislav Levin <slev@altlinux.org>
|
||||
Date: Jan 30 2024 15:11:05 +0000
|
||||
Subject: ipapython: Propagate KRB5Error exceptions on iterating ccache
|
||||
|
||||
|
||||
`ipapython.session_storage.get_data` iterates over
|
||||
credentials in a credential cache till `krb5_cc_next_cred` returns
|
||||
an error. This function doesn't expect any error on calling
|
||||
other kerberos foreign functions during iteration. But that can
|
||||
actually happen and KRB5Error exceptions stop an iteration while
|
||||
they should be propagated.
|
||||
|
||||
With this change iteration will exactly stop on `krb5_cc_next_cred`
|
||||
error as it was supposed to be.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9519
|
||||
Signed-off-by: Stanislav Levin <slev@altlinux.org>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/ipapython/session_storage.py b/ipapython/session_storage.py
|
||||
index dc36f54..e890dc9 100644
|
||||
--- a/ipapython/session_storage.py
|
||||
+++ b/ipapython/session_storage.py
|
||||
@@ -312,8 +312,12 @@ def get_data(princ_name, key):
|
||||
checkcreds = krb5_creds()
|
||||
# the next function will throw an error and break out of the
|
||||
# while loop when we try to access past the last cred
|
||||
- krb5_cc_next_cred(context, ccache, ctypes.byref(cursor),
|
||||
- ctypes.byref(checkcreds))
|
||||
+ try:
|
||||
+ krb5_cc_next_cred(context, ccache, ctypes.byref(cursor),
|
||||
+ ctypes.byref(checkcreds))
|
||||
+ except KRB5Error:
|
||||
+ break
|
||||
+
|
||||
if (krb5_principal_compare(context, principal,
|
||||
checkcreds.client) == 1 and
|
||||
krb5_principal_compare(context, srv_princ,
|
||||
@@ -328,8 +332,6 @@ def get_data(princ_name, key):
|
||||
else:
|
||||
krb5_free_cred_contents(context,
|
||||
ctypes.byref(checkcreds))
|
||||
- except KRB5Error:
|
||||
- pass
|
||||
finally:
|
||||
krb5_cc_end_seq_get(context, ccache, ctypes.byref(cursor))
|
||||
|
||||
|
@ -0,0 +1,67 @@
|
||||
From a343c149838a3058794f33c75c58b75bc1748f7f Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Tue, 17 Sep 2024 17:00:49 +0200
|
||||
Subject: [PATCH] ipatests: provide a ccache to rpcclient deletetrustdom
|
||||
|
||||
With samba update to samba-4.20.4, rpcclient now needs a
|
||||
ccache otherwise it prompts for a password.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9667
|
||||
|
||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
---
|
||||
ipatests/pytest_ipa/integration/tasks.py | 23 ++++++++++++++++++++---
|
||||
1 file changed, 20 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/ipatests/pytest_ipa/integration/tasks.py b/ipatests/pytest_ipa/integration/tasks.py
|
||||
index 9d6b5f67a311a28c335801d59e0ff0f0c7faccdd..677fb7534256a65940fb5280fa6412789dcba54f 100755
|
||||
--- a/ipatests/pytest_ipa/integration/tasks.py
|
||||
+++ b/ipatests/pytest_ipa/integration/tasks.py
|
||||
@@ -795,15 +795,22 @@ def remove_trust_info_from_ad(master, ad_domain, ad_hostname):
|
||||
kinit_as_user(master,
|
||||
'Administrator@{}'.format(ad_domain.upper()),
|
||||
master.config.ad_admin_password)
|
||||
+ # Find cache for the user
|
||||
+ cache_args = []
|
||||
+ cache = get_credential_cache(master)
|
||||
+ if cache:
|
||||
+ cache_args = ["--use-krb5-ccache", cache]
|
||||
+
|
||||
# Detect whether rpcclient supports -k or --use-kerberos option
|
||||
res = master.run_command(['rpcclient', '-h'], raiseonerr=False)
|
||||
if "--use-kerberos" in res.stderr_text:
|
||||
rpcclient_krb5_knob = "--use-kerberos=desired"
|
||||
else:
|
||||
rpcclient_krb5_knob = "-k"
|
||||
- master.run_command(['rpcclient', rpcclient_krb5_knob, ad_hostname,
|
||||
- '-c', 'deletetrustdom {}'.format(master.domain.name)],
|
||||
- raiseonerr=False)
|
||||
+ cmd_args = ['rpcclient', rpcclient_krb5_knob, ad_hostname]
|
||||
+ cmd_args.extend(cache_args)
|
||||
+ cmd_args.extend(['-c', 'deletetrustdom {}'.format(master.domain.name)])
|
||||
+ master.run_command(cmd_args, raiseonerr=False)
|
||||
|
||||
|
||||
def configure_auth_to_local_rule(master, ad):
|
||||
@@ -1086,6 +1093,16 @@ def kinit_admin(host, raiseonerr=True):
|
||||
raiseonerr=raiseonerr)
|
||||
|
||||
|
||||
+def get_credential_cache(host):
|
||||
+ # Return the credential cache currently in use on host or None
|
||||
+ result = host.run_command(["klist"]).stdout_text
|
||||
+ pattern = re.compile(r'Ticket cache: (?P<cache>.*)\n')
|
||||
+ res = pattern.search(result)
|
||||
+ if res:
|
||||
+ return res['cache']
|
||||
+ return None
|
||||
+
|
||||
+
|
||||
def uninstall_master(host, ignore_topology_disconnect=True,
|
||||
ignore_last_of_role=True, clean=True, verbose=False):
|
||||
uninstall_cmd = ['ipa-server-install', '--uninstall', '-U']
|
||||
--
|
||||
2.46.2
|
||||
|
@ -1,109 +0,0 @@
|
||||
From b56a80581ef388e19d5761020454e51463036cd6 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Tue, 23 Jan 2024 14:47:50 +0200
|
||||
Subject: [PATCH] sidgen: ignore staged users when generating SIDs
|
||||
|
||||
Staged users have
|
||||
|
||||
uidNumber: -1
|
||||
gidNumber: -1
|
||||
ipaUniqueID: autogenerate
|
||||
|
||||
We cannot generate ipaSecurityIdentifier based on those UID/GID numbers.
|
||||
However, '-1' value will trigger an error
|
||||
|
||||
find_sid_for_ldap_entry - [file ipa_sidgen_common.c, line 483]: ID value too large.
|
||||
|
||||
And that, in turn, will cause stopping SID generation for all users.
|
||||
|
||||
Detect 'ipaUniqueID: autogenerate' situation and ignore these entries.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9517
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Thierry Bordaz <tbordaz@redhat.com>
|
||||
---
|
||||
daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h | 2 ++
|
||||
.../ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c | 12 ++++++++++++
|
||||
2 files changed, 14 insertions(+)
|
||||
|
||||
diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h
|
||||
index 0feff7eec..bd46982d0 100644
|
||||
--- a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h
|
||||
+++ b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h
|
||||
@@ -45,6 +45,8 @@
|
||||
#define UID_NUMBER "uidnumber"
|
||||
#define GID_NUMBER "gidnumber"
|
||||
#define IPA_SID "ipantsecurityidentifier"
|
||||
+#define IPA_UNIQUEID "ipauniqueid"
|
||||
+#define IPA_UNIQUEID_AUTOGENERATE "autogenerate"
|
||||
#define DOM_ATTRS_FILTER OBJECTCLASS"=ipantdomainattrs"
|
||||
#define DOMAIN_ID_RANGE_FILTER OBJECTCLASS"=ipadomainidrange"
|
||||
#define POSIX_ACCOUNT "posixaccount"
|
||||
diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c
|
||||
index 6f784804c..cb763ebf8 100644
|
||||
--- a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c
|
||||
+++ b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen_common.c
|
||||
@@ -454,6 +454,7 @@ int find_sid_for_ldap_entry(struct slapi_entry *entry,
|
||||
uint32_t id;
|
||||
char *sid = NULL;
|
||||
char **objectclasses = NULL;
|
||||
+ char *uniqueid = NULL;
|
||||
Slapi_PBlock *mod_pb = NULL;
|
||||
Slapi_Mods *smods = NULL;
|
||||
int result;
|
||||
@@ -479,6 +480,16 @@ int find_sid_for_ldap_entry(struct slapi_entry *entry,
|
||||
goto done;
|
||||
}
|
||||
|
||||
+ uniqueid = slapi_entry_attr_get_charptr(entry, IPA_UNIQUEID);
|
||||
+ if (uniqueid != NULL &&
|
||||
+ strncmp(IPA_UNIQUEID_AUTOGENERATE, uniqueid,
|
||||
+ sizeof(IPA_UNIQUEID_AUTOGENERATE)) == 0) {
|
||||
+ LOG("Staged entry [%s] does not have Posix IDs, nothing to do.\n",
|
||||
+ dn_str);
|
||||
+ ret = 0;
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
if (uid_number >= UINT32_MAX || gid_number >= UINT32_MAX) {
|
||||
LOG_FATAL("ID value too large.\n");
|
||||
ret = LDAP_CONSTRAINT_VIOLATION;
|
||||
@@ -554,6 +565,7 @@ int find_sid_for_ldap_entry(struct slapi_entry *entry,
|
||||
}
|
||||
|
||||
done:
|
||||
+ slapi_ch_free_string(&uniqueid);
|
||||
slapi_ch_free_string(&sid);
|
||||
slapi_pblock_destroy(mod_pb);
|
||||
slapi_mods_free(&smods);
|
||||
--
|
||||
2.43.0
|
||||
|
||||
From 07150b71537744f491d022c737ef04775c72a10a Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Tue, 23 Jan 2024 14:53:39 +0200
|
||||
Subject: [PATCH] sidgen: fix missing prototypes
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Thierry Bordaz <tbordaz@redhat.com>
|
||||
---
|
||||
daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h
|
||||
index bd46982d0..aec862796 100644
|
||||
--- a/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h
|
||||
+++ b/daemons/ipa-slapi-plugins/ipa-sidgen/ipa_sidgen.h
|
||||
@@ -106,3 +106,6 @@ int find_sid_for_ldap_entry(struct slapi_entry *entry,
|
||||
const char *base_dn,
|
||||
const char *dom_sid,
|
||||
struct range_info **ranges);
|
||||
+
|
||||
+int sidgen_task_init(Slapi_PBlock *pb);
|
||||
+int ipa_sidgen_init(Slapi_PBlock *pb);
|
||||
--
|
||||
2.43.0
|
||||
|
@ -0,0 +1,60 @@
|
||||
From 743c7b46e463bef666dc84e9f513eb7dee7f59f6 Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Tue, 17 Sep 2024 14:48:58 +0200
|
||||
Subject: [PATCH] test_adtrust_install: add --use-krb5-ccache to smbclient
|
||||
command
|
||||
|
||||
With samba 4.20.4 the smbclient commands needs a ccache otherwise it
|
||||
prompts for a password.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9666
|
||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
---
|
||||
.../test_integration/test_adtrust_install.py | 28 ++++++++++++-------
|
||||
1 file changed, 18 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/ipatests/test_integration/test_adtrust_install.py b/ipatests/test_integration/test_adtrust_install.py
|
||||
index de252db1705ad940c3b5ee4df967d7c17a4203a7..79a91dfaa61276de74b10777c6d44b5942ed1be0 100644
|
||||
--- a/ipatests/test_integration/test_adtrust_install.py
|
||||
+++ b/ipatests/test_integration/test_adtrust_install.py
|
||||
@@ -873,17 +873,25 @@ class TestIpaAdTrustInstall(IntegrationTest):
|
||||
"path", "/freeipa4234"])
|
||||
self.master.run_command(["touch", "before"])
|
||||
self.master.run_command(["touch", "after"])
|
||||
- self.master.run_command(
|
||||
- ["smbclient", "--use-kerberos=desired",
|
||||
- "-c=put before", "//{}/share".format(
|
||||
- self.master.hostname)]
|
||||
- )
|
||||
+ # Find cache for the admin user
|
||||
+ cache_args = []
|
||||
+ cache = tasks.get_credential_cache(self.master)
|
||||
+ if cache:
|
||||
+ cache_args = ["--use-krb5-ccache", cache]
|
||||
+
|
||||
+ cmd_args = ["smbclient", "--use-kerberos=desired"]
|
||||
+ cmd_args.extend(cache_args)
|
||||
+ cmd_args.extend([
|
||||
+ "-c=put before", "//{}/share".format(self.master.hostname)
|
||||
+ ])
|
||||
+ self.master.run_command(cmd_args)
|
||||
self.master.run_command(
|
||||
["net", "conf", "setparm", "share",
|
||||
"valid users", "@admins"])
|
||||
- result = self.master.run_command(
|
||||
- ["smbclient", "--use-kerberos=desired",
|
||||
- "-c=put after", "//{}/share".format(
|
||||
- self.master.hostname)]
|
||||
- )
|
||||
+ cmd_args = ["smbclient", "--use-kerberos=desired"]
|
||||
+ cmd_args.extend(cache_args)
|
||||
+ cmd_args.extend([
|
||||
+ "-c=put after", "//{}/share".format(self.master.hostname)
|
||||
+ ])
|
||||
+ result = self.master.run_command(cmd_args)
|
||||
assert msg not in result.stdout_text
|
||||
--
|
||||
2.46.2
|
||||
|
@ -0,0 +1,209 @@
|
||||
From a785d0c561b8e22bd9d56739481095e07e0a7eb7 Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Mon, 30 Sep 2024 13:30:46 -0400
|
||||
Subject: [PATCH] Don't rely on removing the CA to uninstall the ACME depoyment
|
||||
|
||||
There has always been a pki-server commnd acme-remove. We were
|
||||
not aware that it should be called prior to removing a CA. In
|
||||
11.5.0 this is strongly encouraged by the PKI team. In 11.6.0
|
||||
ACME is treated as a full subsystem so will be removed in the
|
||||
future using pkidestroy -s ACME
|
||||
|
||||
The new class acmeinstance.ACMEInstance is introduced so its
|
||||
uninstallation can be handled in a similar way as the other
|
||||
PKI services via DogtagInstance. It is, right now, a pretty
|
||||
thin wrapper.
|
||||
|
||||
We can discuss moving the ACME installation routines here at
|
||||
some point. It would be ok as long as we don't have to introduce
|
||||
another PKI restart as part of it.
|
||||
|
||||
In PKI 11.6.0 pkidestroy has new options to ensure a clean
|
||||
uninstall: --remove-conf --remove-logs. Pass those options
|
||||
into pkidestroy calls for 11.6.0+.
|
||||
|
||||
Clean up an additional IPA-generated file that needs to be
|
||||
cleaned up during uninstall: /root/kracert.p12. 11.6.0 is
|
||||
more sensitive to leftover files than previous versions.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9673
|
||||
Fixes: https://pagure.io/freeipa/issue/9674
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
---
|
||||
ipaserver/install/acmeinstance.py | 31 +++++++++++++
|
||||
ipaserver/install/ca.py | 5 ++-
|
||||
ipaserver/install/cainstance.py | 1 +
|
||||
ipaserver/install/dogtaginstance.py | 44 +++++++++++++------
|
||||
.../test_integration/test_uninstallation.py | 21 +++++++++
|
||||
5 files changed, 87 insertions(+), 15 deletions(-)
|
||||
create mode 100644 ipaserver/install/acmeinstance.py
|
||||
|
||||
diff --git a/ipaserver/install/acmeinstance.py b/ipaserver/install/acmeinstance.py
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0027c314545f384d9b6ee24b279479e5360d8bef
|
||||
--- /dev/null
|
||||
+++ b/ipaserver/install/acmeinstance.py
|
||||
@@ -0,0 +1,31 @@
|
||||
+#
|
||||
+# Copyright (C) 2024 FreeIPA Contributors see COPYING for license
|
||||
+#
|
||||
+
|
||||
+import logging
|
||||
+
|
||||
+from ipaserver.install.dogtaginstance import DogtagInstance
|
||||
+
|
||||
+logger = logging.getLogger(__name__)
|
||||
+
|
||||
+
|
||||
+class ACMEInstance(DogtagInstance):
|
||||
+ """
|
||||
+ ACME is deployed automatically with a CA subsystem but it is the
|
||||
+ responsibility of IPA to uninstall the service.
|
||||
+
|
||||
+ This is mostly a placeholder for the uninstaller. We can
|
||||
+ eventually move the ACME installation routines into this class
|
||||
+ if we want but it might result in an extra PKI restart which
|
||||
+ would be slow.
|
||||
+ """
|
||||
+ def __init__(self, realm=None, host_name=None):
|
||||
+ super(ACMEInstance, self).__init__(
|
||||
+ realm=realm,
|
||||
+ subsystem="ACME",
|
||||
+ service_desc="ACME server",
|
||||
+ host_name=host_name
|
||||
+ )
|
||||
+
|
||||
+ def uninstall(self):
|
||||
+ DogtagInstance.uninstall(self)
|
||||
diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py
|
||||
index ffcb5268399ce71128fc8de5f54d433d35e99dd2..520e3fc5de1084e7c22c0cf7eaa86e1d3c421373 100644
|
||||
--- a/ipaserver/install/ca.py
|
||||
+++ b/ipaserver/install/ca.py
|
||||
@@ -22,7 +22,7 @@ from ipaplatform.constants import constants
|
||||
from ipaserver.install import sysupgrade
|
||||
from ipapython.install import typing
|
||||
from ipapython.install.core import group, knob, extend_knob
|
||||
-from ipaserver.install import cainstance, bindinstance, dsinstance
|
||||
+from ipaserver.install import acmeinstance, cainstance, bindinstance, dsinstance
|
||||
from ipapython import ipautil, certdb
|
||||
from ipapython import ipaldap
|
||||
from ipapython.admintool import ScriptError
|
||||
@@ -715,6 +715,9 @@ def install_step_1(standalone, replica_config, options, custodia):
|
||||
|
||||
|
||||
def uninstall():
|
||||
+ acme = acmeinstance.ACMEInstance(api.env.realm)
|
||||
+ acme.uninstall()
|
||||
+
|
||||
ca_instance = cainstance.CAInstance(api.env.realm)
|
||||
ca_instance.stop_tracking_certificates()
|
||||
ipautil.remove_file(paths.RA_AGENT_PEM)
|
||||
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
|
||||
index 5dac2c0441752e7bb569cde1fc93bc17c3128cdf..5c2c9f8b981cf5d587865f7680e2b231eae655e2 100644
|
||||
--- a/ipaserver/install/cainstance.py
|
||||
+++ b/ipaserver/install/cainstance.py
|
||||
@@ -1118,6 +1118,7 @@ class CAInstance(DogtagInstance):
|
||||
|
||||
ipautil.remove_file(paths.DOGTAG_ADMIN_P12)
|
||||
ipautil.remove_file(paths.CACERT_P12)
|
||||
+ ipautil.remove_file(paths.ADMIN_CERT_PATH)
|
||||
|
||||
def unconfigure_certmonger_renewal_guard(self):
|
||||
if not self.is_configured():
|
||||
diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py
|
||||
index e89492312deb8ca20668a62fd7a2a20e2866a3fb..4b0f4d274b0c33140ed6f939f1a3fd8b75930ff9 100644
|
||||
--- a/ipaserver/install/dogtaginstance.py
|
||||
+++ b/ipaserver/install/dogtaginstance.py
|
||||
@@ -304,21 +304,37 @@ class DogtagInstance(service.Service):
|
||||
if self.is_installed():
|
||||
self.print_msg("Unconfiguring %s" % self.subsystem)
|
||||
|
||||
- args = [paths.PKIDESTROY,
|
||||
- "-i", "pki-tomcat", "--force",
|
||||
- "-s", self.subsystem]
|
||||
-
|
||||
- # specify --log-file <path> on PKI 11.0.0 or later
|
||||
-
|
||||
+ args = []
|
||||
pki_version = pki.util.Version(pki.specification_version())
|
||||
- if pki_version >= pki.util.Version("11.0.0"):
|
||||
- timestamp = time.strftime(
|
||||
- "%Y%m%d%H%M%S",
|
||||
- time.localtime(time.time()))
|
||||
- log_file = os.path.join(
|
||||
- paths.VAR_LOG_PKI_DIR,
|
||||
- "pki-%s-destroy.%s.log" % (self.subsystem.lower(), timestamp))
|
||||
- args.extend(["--log-file", log_file])
|
||||
+ if self.subsystem == "ACME":
|
||||
+ if pki_version < pki.util.Version("11.0.0"):
|
||||
+ return
|
||||
+ elif (
|
||||
+ pki.util.Version("11.0.0") <= pki_version
|
||||
+ <= pki.util.Version("11.5.0")
|
||||
+ ):
|
||||
+ args = ['pki-server', 'acme-remove']
|
||||
+ else:
|
||||
+ # fall through for PKI >= 11.6.0
|
||||
+ pass
|
||||
+ if not args:
|
||||
+ args = [paths.PKIDESTROY,
|
||||
+ "-i", "pki-tomcat", "--force",
|
||||
+ "-s", self.subsystem]
|
||||
+
|
||||
+ # specify --log-file <path> on PKI 11.0.0 or later
|
||||
+
|
||||
+ if pki_version >= pki.util.Version("11.0.0"):
|
||||
+ timestamp = time.strftime(
|
||||
+ "%Y%m%d%H%M%S",
|
||||
+ time.localtime(time.time()))
|
||||
+ log_file = os.path.join(
|
||||
+ paths.VAR_LOG_PKI_DIR,
|
||||
+ "pki-%s-destroy.%s.log" %
|
||||
+ (self.subsystem.lower(), timestamp))
|
||||
+ args.extend(["--log-file", log_file])
|
||||
+ if pki_version >= pki.util.Version("11.6.0"):
|
||||
+ args.extend(["--remove-conf", "--remove-logs"])
|
||||
|
||||
try:
|
||||
ipautil.run(args)
|
||||
diff --git a/ipatests/test_integration/test_uninstallation.py b/ipatests/test_integration/test_uninstallation.py
|
||||
index 4f8f17ce3ad8d5376ecba11442f379e5691de7f7..049c50db536ae1070f5f958e76b12a1518da0aba 100644
|
||||
--- a/ipatests/test_integration/test_uninstallation.py
|
||||
+++ b/ipatests/test_integration/test_uninstallation.py
|
||||
@@ -197,6 +197,7 @@ class TestUninstallCleanup(IntegrationTest):
|
||||
'/var/lib/sss/pubconf/krb5.include.d/localauth_plugin',
|
||||
'/var/named/dynamic/managed-keys.bind',
|
||||
'/var/named/dynamic/managed-keys.bind.jnl',
|
||||
+ '/var/lib/systemd/coredump/',
|
||||
]
|
||||
|
||||
leftovers = []
|
||||
@@ -217,3 +218,23 @@ class TestUninstallCleanup(IntegrationTest):
|
||||
leftovers.append(line)
|
||||
|
||||
assert len(leftovers) == 0
|
||||
+
|
||||
+
|
||||
+class TestUninstallReinstall(IntegrationTest):
|
||||
+ """Test install, uninstall, re-install.
|
||||
+
|
||||
+ Reinstall with PKI 11.6.0 was failing
|
||||
+ https://pagure.io/freeipa/issue/9673
|
||||
+ """
|
||||
+
|
||||
+ num_replicas = 0
|
||||
+
|
||||
+ @classmethod
|
||||
+ def install(cls, mh):
|
||||
+ tasks.install_master(cls.master, setup_dns=False)
|
||||
+
|
||||
+ def test_uninstall_server(self):
|
||||
+ tasks.uninstall_master(self.master)
|
||||
+
|
||||
+ def test_reinstall_server(self):
|
||||
+ tasks.install_master(self.master, setup_dns=False)
|
||||
--
|
||||
2.46.2
|
||||
|
@ -1,310 +0,0 @@
|
||||
From 67ca47ba4092811029eec02f8af9c34ba7662924 Mon Sep 17 00:00:00 2001
|
||||
From: Julien Rische <jrische@redhat.com>
|
||||
Date: Mon, 9 Oct 2023 15:47:03 +0200
|
||||
Subject: [PATCH] ipa-kdb: Ensure Bronze-Bit check can be enabled
|
||||
|
||||
MIT krb5 1.19 and older do not implement support for PAC ticket
|
||||
signature to protect the encrypted part of tickets. This is the cause of
|
||||
the Bronze-Bit vulnerability (CVE-2020-17043). The Bronze-Bit attack
|
||||
detection mechanism introduced in a847e248 relies on the content of the
|
||||
PAC.
|
||||
|
||||
However, since CVE-2022-37967, the content of the PAC can no longer be
|
||||
trusted if the KDC does not support PAC extended KDC signature (aka.
|
||||
PAC full checksum). This signature is supported in MIT krb5 since
|
||||
version 1.21.
|
||||
|
||||
Support for the PAC extended KDC signature was backported downstream to
|
||||
krb5 1.18.2 for CentOS 8 Stream (dist-git commit 7d215a54). This makes
|
||||
the content of the PAC still trustworthy there.
|
||||
|
||||
This commit disables the Bronze-Bit attack detection mechanism at build
|
||||
time in case krb5 does not provide the krb5_pac_full_sign_compat()
|
||||
function.
|
||||
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
---
|
||||
daemons/ipa-kdb/ipa_kdb.h | 4 ++++
|
||||
daemons/ipa-kdb/ipa_kdb_kdcpolicy.c | 7 +++++++
|
||||
daemons/ipa-kdb/ipa_kdb_mspac.c | 4 ++++
|
||||
3 files changed, 15 insertions(+)
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
|
||||
index 02b2cb631..c6926f7d5 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb.h
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb.h
|
||||
@@ -367,6 +367,8 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
|
||||
const char *test_realm, size_t size,
|
||||
char **trusted_realm);
|
||||
|
||||
+#if KRB5_KDB_DAL_MAJOR_VERSION <= 8
|
||||
+# ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT
|
||||
/* Try to detect a Bronze-Bit attack based on the content of the request and
|
||||
* data from the KDB.
|
||||
*
|
||||
@@ -379,6 +381,8 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
|
||||
krb5_error_code
|
||||
ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
|
||||
bool *detected, const char **status);
|
||||
+# endif
|
||||
+#endif
|
||||
|
||||
/* DELEGATION CHECKS */
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
|
||||
index 1032dff0b..ee0546c01 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
|
||||
@@ -185,11 +185,18 @@ ipa_kdcpolicy_check_tgs(krb5_context context, krb5_kdcpolicy_moddata moddata,
|
||||
const char **status, krb5_deltat *lifetime_out,
|
||||
krb5_deltat *renew_lifetime_out)
|
||||
{
|
||||
+#if KRB5_KDB_DAL_MAJOR_VERSION <= 8
|
||||
+# ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT
|
||||
krb5_error_code kerr;
|
||||
|
||||
kerr = ipadb_check_for_bronze_bit_attack(context, request, NULL, status);
|
||||
if (kerr)
|
||||
return KRB5KDC_ERR_POLICY;
|
||||
+# else
|
||||
+# warning Support for Kerberos PAC extended KDC signature is missing.\
|
||||
+ This makes FreeIPA vulnerable to the Bronze-Bit exploit (CVE-2020-17049).
|
||||
+# endif
|
||||
+#endif
|
||||
|
||||
*status = NULL;
|
||||
*lifetime_out = 0;
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
index b4e22d431..05d5b407d 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
@@ -3299,6 +3299,8 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
|
||||
return KRB5_KDB_NOENTRY;
|
||||
}
|
||||
|
||||
+#if KRB5_KDB_DAL_MAJOR_VERSION <= 8
|
||||
+# ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT
|
||||
krb5_error_code
|
||||
ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
|
||||
bool *detected, const char **status)
|
||||
@@ -3471,3 +3473,5 @@ end:
|
||||
ipadb_free_principal(context, proxy_entry);
|
||||
return kerr;
|
||||
}
|
||||
+# endif
|
||||
+#endif
|
||||
--
|
||||
2.43.0
|
||||
|
||||
From 27b96c17dd51d076e04d97662b7c788658a5094a Mon Sep 17 00:00:00 2001
|
||||
From: Julien Rische <jrische@redhat.com>
|
||||
Date: Jan 26 2024 09:35:57 +0000
|
||||
Subject: ipa-kdb: Disable Bronze-Bit check if PAC not available
|
||||
|
||||
|
||||
The Bronze-Bit check introduced in commit
|
||||
a847e2483b4c4832ee5129901da169f4eb0d1392 requires the MS-PAC to be
|
||||
present in the evidence ticket in order for S4U2Proxy requests to be
|
||||
accepted. This actually requires SIDs to be set.
|
||||
|
||||
However, domains that were initialized before commit
|
||||
e527857d000e558b3288a7a210400abaf2171237 may still not have SIDs
|
||||
configured. This would results in all S4U2Proxy requests to fail
|
||||
(including all the HTTP API requests).
|
||||
|
||||
This present commit disables the check for the Bronze-Bit exploit
|
||||
(CVE-2020-17049) in case the domain is not able to generate PACs.
|
||||
Instead, it prints a warning message in the KDC logs each time a
|
||||
S4U2Proxy request is processed.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9521
|
||||
|
||||
Signed-off-by: Julien Rische <jrische@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
|
||||
index c6926f7..621c235 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb.h
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb.h
|
||||
@@ -370,17 +370,21 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
|
||||
#if KRB5_KDB_DAL_MAJOR_VERSION <= 8
|
||||
# ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT
|
||||
/* Try to detect a Bronze-Bit attack based on the content of the request and
|
||||
- * data from the KDB.
|
||||
+ * data from the KDB. This check will work only if the domain supports MS-PAC.
|
||||
*
|
||||
* context krb5 context
|
||||
* request KDB request
|
||||
- * detected Set to "true" if a bronze bit attack is detected and the
|
||||
- * pointer is not NULL. Remains unset otherwise.
|
||||
+ * supported If not NULL, set to "false" in case the Bronze-Bit exploit
|
||||
+ * detection process silently failed to complete because the
|
||||
+ * domain does not meet requirements. Set to "true" otherwise.
|
||||
+ * detected If not NULL, set to "true" if a Bronze-Bit attack is detected.
|
||||
+ * Set to "false" otherwise.
|
||||
* status If the call fails and the pointer is not NULL, set it with a
|
||||
* message describing the cause of the failure. */
|
||||
krb5_error_code
|
||||
ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
|
||||
- bool *detected, const char **status);
|
||||
+ bool *supported, bool *detected,
|
||||
+ const char **status);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
|
||||
index ee0546c..713e9a0 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
|
||||
@@ -188,10 +188,18 @@ ipa_kdcpolicy_check_tgs(krb5_context context, krb5_kdcpolicy_moddata moddata,
|
||||
#if KRB5_KDB_DAL_MAJOR_VERSION <= 8
|
||||
# ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT
|
||||
krb5_error_code kerr;
|
||||
+ bool supported;
|
||||
|
||||
- kerr = ipadb_check_for_bronze_bit_attack(context, request, NULL, status);
|
||||
+ kerr = ipadb_check_for_bronze_bit_attack(context, request, supported, NULL,
|
||||
+ status);
|
||||
if (kerr)
|
||||
return KRB5KDC_ERR_POLICY;
|
||||
+
|
||||
+ if (!supported)
|
||||
+ krb5_klog_syslog(LOG_WARNING, "MS-PAC not available. This makes "
|
||||
+ "FreeIPA vulnerable to the Bronze-Bit exploit "
|
||||
+ "(CVE-2020-17049). Please generate SIDs to enable "
|
||||
+ "PAC support.");
|
||||
# else
|
||||
# warning Support for Kerberos PAC extended KDC signature is missing.\
|
||||
This makes FreeIPA vulnerable to the Bronze-Bit exploit (CVE-2020-17049).
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
index 05d5b40..a18beff 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
@@ -3303,11 +3303,14 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
|
||||
# ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT
|
||||
krb5_error_code
|
||||
ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
|
||||
- bool *detected, const char **status)
|
||||
+ bool *supported, bool *detected,
|
||||
+ const char **status)
|
||||
{
|
||||
krb5_error_code kerr;
|
||||
const char *st = NULL;
|
||||
size_t i, j;
|
||||
+ bool in_supported = true, in_detected = false;
|
||||
+ struct ipadb_context *ipactx;
|
||||
krb5_ticket *evidence_tkt;
|
||||
krb5_authdata **authdata, **ifrel = NULL;
|
||||
krb5_pac pac = NULL;
|
||||
@@ -3327,6 +3330,21 @@ ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
|
||||
goto end;
|
||||
}
|
||||
|
||||
+ ipactx = ipadb_get_context(context);
|
||||
+ if (!ipactx) {
|
||||
+ kerr = KRB5_KDB_DBNOTINITED;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ /* Handle the case where the domain is not able to generate PACs (probably
|
||||
+ * because SIDs are not set). In this case, we just skip the Bronze-Bit
|
||||
+ * check. */
|
||||
+ if (!ipactx->mspac) {
|
||||
+ in_supported = false;
|
||||
+ kerr = 0;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
evidence_tkt = request->second_ticket[0];
|
||||
|
||||
/* No need to check the Forwardable flag. If it was not set, this request
|
||||
@@ -3451,8 +3469,7 @@ ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
|
||||
/* This evidence ticket cannot be forwardable given the privileges
|
||||
* of the proxy principal.
|
||||
* This is a Bronze Bit attack. */
|
||||
- if (detected)
|
||||
- *detected = true;
|
||||
+ in_detected = true;
|
||||
st = "S4U2PROXY_BRONZE_BIT_ATTACK_DETECTED";
|
||||
kerr = EBADE;
|
||||
goto end;
|
||||
@@ -3464,6 +3481,10 @@ ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
|
||||
end:
|
||||
if (st && status)
|
||||
*status = st;
|
||||
+ if (supported)
|
||||
+ *supported = in_supported;
|
||||
+ if (detected)
|
||||
+ *detected = in_detected;
|
||||
|
||||
krb5_free_authdata(context, ifrel);
|
||||
krb5_pac_free(context, pac);
|
||||
|
||||
From 81aa6ef695838a4b2fb5a53e773ea379a492913d Mon Sep 17 00:00:00 2001
|
||||
From: Julien Rische <jrische@redhat.com>
|
||||
Date: Fri, 9 Feb 2024 16:36:03 +0100
|
||||
Subject: [PATCH] ipd-kdb: Fix some mistakes in
|
||||
ipadb_check_for_bronze_bit_attack()
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9521
|
||||
Signed-off-by: Julien Rische <jrische@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abbra@users.noreply.github.com>
|
||||
---
|
||||
daemons/ipa-kdb/ipa_kdb.h | 3 ++-
|
||||
daemons/ipa-kdb/ipa_kdb_kdcpolicy.c | 2 +-
|
||||
daemons/ipa-kdb/ipa_kdb_mspac.c | 5 +++--
|
||||
3 files changed, 6 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
|
||||
index 621c23591..5de5ea7a5 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb.h
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb.h
|
||||
@@ -382,7 +382,8 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
|
||||
* status If the call fails and the pointer is not NULL, set it with a
|
||||
* message describing the cause of the failure. */
|
||||
krb5_error_code
|
||||
-ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
|
||||
+ipadb_check_for_bronze_bit_attack(krb5_context context,
|
||||
+ const krb5_kdc_req *request,
|
||||
bool *supported, bool *detected,
|
||||
const char **status);
|
||||
# endif
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
|
||||
index 713e9a0c8..44959f3de 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
|
||||
@@ -190,7 +190,7 @@ ipa_kdcpolicy_check_tgs(krb5_context context, krb5_kdcpolicy_moddata moddata,
|
||||
krb5_error_code kerr;
|
||||
bool supported;
|
||||
|
||||
- kerr = ipadb_check_for_bronze_bit_attack(context, request, supported, NULL,
|
||||
+ kerr = ipadb_check_for_bronze_bit_attack(context, request, &supported, NULL,
|
||||
status);
|
||||
if (kerr)
|
||||
return KRB5KDC_ERR_POLICY;
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
index 80350364a..886ed7785 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
@@ -3308,13 +3308,14 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
|
||||
#if KRB5_KDB_DAL_MAJOR_VERSION <= 8
|
||||
# ifdef HAVE_KRB5_PAC_FULL_SIGN_COMPAT
|
||||
krb5_error_code
|
||||
-ipadb_check_for_bronze_bit_attack(krb5_context context, krb5_kdc_req *request,
|
||||
+ipadb_check_for_bronze_bit_attack(krb5_context context,
|
||||
+ const krb5_kdc_req *request,
|
||||
bool *supported, bool *detected,
|
||||
const char **status)
|
||||
{
|
||||
krb5_error_code kerr;
|
||||
const char *st = NULL;
|
||||
- size_t i, j;
|
||||
+ size_t i, j = 0;
|
||||
bool in_supported = true, in_detected = false;
|
||||
struct ipadb_context *ipactx;
|
||||
krb5_ticket *evidence_tkt;
|
||||
--
|
||||
2.43.0
|
||||
|
@ -0,0 +1,35 @@
|
||||
From ae4c2ad6cd966d48c063814f494dcc16cf0ccd4c Mon Sep 17 00:00:00 2001
|
||||
From: Sudhir Menon <sumenon@redhat.com>
|
||||
Date: Tue, 24 Sep 2024 13:46:48 +0530
|
||||
Subject: [PATCH] ipatests: Fixes for ipa-idrange-fix testsuite
|
||||
|
||||
This patch adds the line tasks.install_master(cls.master).
|
||||
The kinit admin command fails with the below error as the
|
||||
IPA is not configured on the test system
|
||||
|
||||
'ipa: ERROR: stderr: kinit: Configuration file does not specify default
|
||||
realm when parsing name admin'
|
||||
|
||||
Signed-off-by: Sudhir Menon <sumenon@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipatests/test_integration/test_ipa_idrange_fix.py | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/ipatests/test_integration/test_ipa_idrange_fix.py b/ipatests/test_integration/test_ipa_idrange_fix.py
|
||||
index ff8fbdac9d028d26fc55f5e357f89af879a61723..0c915bd0931ed11a3aa86c533ee8748aa8a7ec07 100644
|
||||
--- a/ipatests/test_integration/test_ipa_idrange_fix.py
|
||||
+++ b/ipatests/test_integration/test_ipa_idrange_fix.py
|
||||
@@ -17,6 +17,9 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestIpaIdrangeFix(IntegrationTest):
|
||||
+
|
||||
+ topology = 'line'
|
||||
+
|
||||
@classmethod
|
||||
def install(cls, mh):
|
||||
super(TestIpaIdrangeFix, cls).install(mh)
|
||||
--
|
||||
2.46.2
|
||||
|
@ -1,272 +0,0 @@
|
||||
From 00f8ddbfd2795228b343e1c39c1944b44d482c18 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Fri, 24 Nov 2023 11:46:19 +0200
|
||||
Subject: [PATCH 1/4] ipa-kdb: add better detection of allowed user auth type
|
||||
|
||||
If default user authentication type is set to a list that does not
|
||||
include a password or a hardened credential, the resulting configuration
|
||||
might be incorrect for special service principals, including a krbtgt/..
|
||||
one.
|
||||
|
||||
Add detection of special principals to avoid these situations and always
|
||||
allow password or hardened for services.
|
||||
|
||||
Special handling is needed for the following principals:
|
||||
|
||||
- krbtgt/.. -- TGT service principals
|
||||
- K/M -- master key principal
|
||||
- kadmin/changepw -- service for changing passwords
|
||||
- kadmin/kadmin -- kadmin service principal
|
||||
- kadmin/history -- key used to encrypt history
|
||||
|
||||
Additionally, implicitly allow password or hardened credential use for
|
||||
IPA services and IPA hosts since applications typically use keytabs for
|
||||
that purpose.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9485
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
|
||||
---
|
||||
daemons/ipa-kdb/ipa_kdb.c | 62 ++++++++++++++++++++++++++++++++++-----
|
||||
1 file changed, 54 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c
|
||||
index 06d511c76..dbb98dba6 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb.c
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "ipa_kdb.h"
|
||||
#include "ipa_krb5.h"
|
||||
#include "ipa_hostname.h"
|
||||
+#include <kadm5/admin.h>
|
||||
|
||||
#define IPADB_GLOBAL_CONFIG_CACHE_TIME 60
|
||||
|
||||
@@ -207,6 +208,19 @@ static const struct {
|
||||
{ "idp", IPADB_USER_AUTH_IDP },
|
||||
{ "passkey", IPADB_USER_AUTH_PASSKEY },
|
||||
{ }
|
||||
+},
|
||||
+ objclass_table[] = {
|
||||
+ { "ipaservice", IPADB_USER_AUTH_PASSWORD },
|
||||
+ { "ipahost", IPADB_USER_AUTH_PASSWORD },
|
||||
+ { }
|
||||
+},
|
||||
+ princname_table[] = {
|
||||
+ { KRB5_TGS_NAME, IPADB_USER_AUTH_PASSWORD },
|
||||
+ { KRB5_KDB_M_NAME, IPADB_USER_AUTH_PASSWORD },
|
||||
+ { KADM5_ADMIN_SERVICE, IPADB_USER_AUTH_PASSWORD },
|
||||
+ { KADM5_CHANGEPW_SERVICE, IPADB_USER_AUTH_PASSWORD },
|
||||
+ { KADM5_HIST_PRINCIPAL, IPADB_USER_AUTH_PASSWORD },
|
||||
+ { }
|
||||
};
|
||||
|
||||
void ipadb_parse_user_auth(LDAP *lcontext, LDAPMessage *le,
|
||||
@@ -217,17 +231,49 @@ void ipadb_parse_user_auth(LDAP *lcontext, LDAPMessage *le,
|
||||
|
||||
*userauth = IPADB_USER_AUTH_NONE;
|
||||
vals = ldap_get_values_len(lcontext, le, IPA_USER_AUTH_TYPE);
|
||||
- if (!vals)
|
||||
- return;
|
||||
-
|
||||
- for (i = 0; vals[i]; i++) {
|
||||
- for (j = 0; userauth_table[j].name; j++) {
|
||||
- if (strcasecmp(vals[i]->bv_val, userauth_table[j].name) == 0) {
|
||||
- *userauth |= userauth_table[j].flag;
|
||||
- break;
|
||||
+ if (!vals) {
|
||||
+ /* if there is no explicit ipaUserAuthType set, use objectclass */
|
||||
+ vals = ldap_get_values_len(lcontext, le, "objectclass");
|
||||
+ if (!vals)
|
||||
+ return;
|
||||
+
|
||||
+ for (i = 0; vals[i]; i++) {
|
||||
+ for (j = 0; objclass_table[j].name; j++) {
|
||||
+ if (strcasecmp(vals[i]->bv_val, objclass_table[j].name) == 0) {
|
||||
+ *userauth |= objclass_table[j].flag;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ for (i = 0; vals[i]; i++) {
|
||||
+ for (j = 0; userauth_table[j].name; j++) {
|
||||
+ if (strcasecmp(vals[i]->bv_val, userauth_table[j].name) == 0) {
|
||||
+ *userauth |= userauth_table[j].flag;
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
||||
+
|
||||
+ /* If neither ipaUserAuthType nor objectClass were definitive,
|
||||
+ * check the krbPrincipalName to see if it is krbtgt/ or K/M one */
|
||||
+ if (*userauth == IPADB_USER_AUTH_NONE) {
|
||||
+ ldap_value_free_len(vals);
|
||||
+ vals = ldap_get_values_len(lcontext, le, "krbprincipalname");
|
||||
+ if (!vals)
|
||||
+ return;
|
||||
+ for (i = 0; vals[i]; i++) {
|
||||
+ for (j = 0; princname_table[j].name; j++) {
|
||||
+ if (strncmp(vals[i]->bv_val, princname_table[j].name,
|
||||
+ strlen(princname_table[j].name)) == 0) {
|
||||
+ *userauth |= princname_table[j].flag;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ }
|
||||
/* If password auth is enabled, enable hardened policy too. */
|
||||
if (*userauth & IPADB_USER_AUTH_PASSWORD) {
|
||||
*userauth |= IPADB_USER_AUTH_HARDENED;
|
||||
--
|
||||
2.43.0
|
||||
|
||||
|
||||
From 69ae9febfb4462766b3bfe3e07e76550ece97b42 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Fri, 24 Nov 2023 11:54:04 +0200
|
||||
Subject: [PATCH 2/4] ipa-kdb: when applying ticket policy, do not deny PKINIT
|
||||
|
||||
PKINIT differs from other pre-authentication methods by the fact that it
|
||||
can be matched indepedently of the user authentication types via certmap
|
||||
plugin in KDC.
|
||||
|
||||
Since PKINIT is a strong authentication method, allow its authentication
|
||||
indicator and only apply the ticket policy.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9485
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
|
||||
---
|
||||
daemons/ipa-kdb/ipa_kdb_kdcpolicy.c | 7 ++-----
|
||||
1 file changed, 2 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
|
||||
index 436ee0e62..2802221c7 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_kdcpolicy.c
|
||||
@@ -119,11 +119,8 @@ ipa_kdcpolicy_check_as(krb5_context context, krb5_kdcpolicy_moddata moddata,
|
||||
pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_RADIUS]);
|
||||
} else if (strcmp(auth_indicator, "pkinit") == 0) {
|
||||
valid_auth_indicators++;
|
||||
- if (!(ua & IPADB_USER_AUTH_PKINIT)) {
|
||||
- *status = "PKINIT pre-authentication not allowed for this user.";
|
||||
- kerr = KRB5KDC_ERR_POLICY;
|
||||
- goto done;
|
||||
- }
|
||||
+ /* allow PKINIT unconditionally -- it has passed already at this
|
||||
+ * point so some certificate was useful, only apply the limits */
|
||||
pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_PKINIT]);
|
||||
} else if (strcmp(auth_indicator, "hardened") == 0) {
|
||||
valid_auth_indicators++;
|
||||
--
|
||||
2.43.0
|
||||
|
||||
|
||||
From 62c44c9e69aa2721990ca3628434713e1af6f59b Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Fri, 24 Nov 2023 12:20:55 +0200
|
||||
Subject: [PATCH 3/4] ipa-kdb: clarify user auth table mapping use of
|
||||
_AUTH_PASSWORD
|
||||
|
||||
Related: https://pagure.io/freeipa/issue/9485
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
|
||||
---
|
||||
daemons/ipa-kdb/ipa_kdb.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c
|
||||
index dbb98dba6..4e6cacf24 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb.c
|
||||
@@ -195,6 +195,9 @@ done:
|
||||
return base;
|
||||
}
|
||||
|
||||
+/* In this table all _AUTH_PASSWORD entries will be
|
||||
+ * expanded to include _AUTH_HARDENED in ipadb_parse_user_auth()
|
||||
+ * which means there is no need to explicitly add it here */
|
||||
static const struct {
|
||||
const char *name;
|
||||
enum ipadb_user_auth flag;
|
||||
--
|
||||
2.43.0
|
||||
|
||||
|
||||
From c3bc938650b19a51706d8ccd98cdf8deaa26dc28 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Fri, 24 Nov 2023 13:00:48 +0200
|
||||
Subject: [PATCH 4/4] ipatests: make sure PKINIT enrollment works with a strict
|
||||
policy
|
||||
|
||||
Previously, for a global policy which does not include
|
||||
'password', krb5kdc restart was failing. Now it should succeed.
|
||||
|
||||
We set admin user authentication type to PASSWORD to simplify
|
||||
configuration in the test.
|
||||
|
||||
What matters here is that global policy does not include PKINIT and that
|
||||
means a code in the ticket policy check will allow PKINIT implicitly
|
||||
rather than explicitly.
|
||||
|
||||
Related: https://pagure.io/freeipa/issue/9485
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Francisco Trivino <ftrivino@redhat.com>
|
||||
---
|
||||
.../test_integration/test_pkinit_install.py | 26 +++++++++++++++++++
|
||||
1 file changed, 26 insertions(+)
|
||||
|
||||
diff --git a/ipatests/test_integration/test_pkinit_install.py b/ipatests/test_integration/test_pkinit_install.py
|
||||
index caa0e6a34..5c2e7af02 100644
|
||||
--- a/ipatests/test_integration/test_pkinit_install.py
|
||||
+++ b/ipatests/test_integration/test_pkinit_install.py
|
||||
@@ -23,6 +23,24 @@ class TestPkinitClientInstall(IntegrationTest):
|
||||
def install(cls, mh):
|
||||
tasks.install_master(cls.master)
|
||||
|
||||
+ def enforce_password_and_otp(self):
|
||||
+ """enforce otp by default and password for admin """
|
||||
+ self.master.run_command(
|
||||
+ [
|
||||
+ "ipa",
|
||||
+ "config-mod",
|
||||
+ "--user-auth-type=otp",
|
||||
+ ]
|
||||
+ )
|
||||
+ self.master.run_command(
|
||||
+ [
|
||||
+ "ipa",
|
||||
+ "user-mod",
|
||||
+ "admin",
|
||||
+ "--user-auth-type=password",
|
||||
+ ]
|
||||
+ )
|
||||
+
|
||||
def add_certmaperule(self):
|
||||
"""add certmap rule to map SAN dNSName to host entry"""
|
||||
self.master.run_command(
|
||||
@@ -86,6 +104,14 @@ class TestPkinitClientInstall(IntegrationTest):
|
||||
cabundle = self.master.get_file_contents(paths.KDC_CA_BUNDLE_PEM)
|
||||
client.put_file_contents(self.tmpbundle, cabundle)
|
||||
|
||||
+ def test_restart_krb5kdc(self):
|
||||
+ tasks.kinit_admin(self.master)
|
||||
+ self.enforce_password_and_otp()
|
||||
+ self.master.run_command(['systemctl', 'stop', 'krb5kdc.service'])
|
||||
+ self.master.run_command(['systemctl', 'start', 'krb5kdc.service'])
|
||||
+ self.master.run_command(['systemctl', 'stop', 'kadmin.service'])
|
||||
+ self.master.run_command(['systemctl', 'start', 'kadmin.service'])
|
||||
+
|
||||
def test_client_install_pkinit(self):
|
||||
tasks.kinit_admin(self.master)
|
||||
self.add_certmaperule()
|
||||
--
|
||||
2.43.0
|
||||
|
@ -0,0 +1,265 @@
|
||||
From 18303b94bea4e08a0c889fc357df6ba2f308fa0d Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Wed, 2 Oct 2024 21:26:34 -0400
|
||||
Subject: [PATCH] Do not let user with an expired OTP token to log in if only
|
||||
OTP is allowed
|
||||
|
||||
If only OTP authentication is allowed, and a user tries to login with an
|
||||
expired token, do not let them log in with their password. Forcing the
|
||||
admin to intervene. If the user does not have an OTP token then allow
|
||||
them to log in with a password until an OTP token is configured
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9387
|
||||
|
||||
Signed-off-by: Mark Reynolds <mreynolds@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Julien Rische <jrische@redhat.com>
|
||||
---
|
||||
daemons/ipa-kdb/ipa_kdb_principals.c | 63 +++++++++++--
|
||||
.../ipa-slapi-plugins/ipa-pwd-extop/prepost.c | 3 +-
|
||||
ipatests/test_integration/test_otp.py | 94 ++++++++++++++++++-
|
||||
3 files changed, 151 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c
|
||||
index 14603e528b43acb29234c425e97ad297ac6724a7..114957b884786dd3ca3b01c47f6bb82e8a040beb 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_principals.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_principals.c
|
||||
@@ -107,7 +107,6 @@ static char *std_principal_obj_classes[] = {
|
||||
"krbprincipal",
|
||||
"krbprincipalaux",
|
||||
"krbTicketPolicyAux",
|
||||
-
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -338,14 +337,16 @@ static void ipadb_validate_otp(struct ipadb_context *ipactx,
|
||||
if (dn == NULL)
|
||||
return;
|
||||
count = asprintf(&filter, ftmpl, dn, datetime, datetime);
|
||||
- ldap_memfree(dn);
|
||||
- if (count < 0)
|
||||
+ if (count < 0) {
|
||||
+ ldap_memfree(dn);
|
||||
return;
|
||||
+ }
|
||||
|
||||
/* Fetch the active token list. */
|
||||
kerr = ipadb_simple_search(ipactx, ipactx->base, LDAP_SCOPE_SUBTREE,
|
||||
filter, (char**) attrs, &res);
|
||||
free(filter);
|
||||
+ filter = NULL;
|
||||
if (kerr != 0 || res == NULL)
|
||||
return;
|
||||
|
||||
@@ -353,10 +354,60 @@ static void ipadb_validate_otp(struct ipadb_context *ipactx,
|
||||
count = ldap_count_entries(ipactx->lcontext, res);
|
||||
ldap_msgfree(res);
|
||||
|
||||
- /* If the user is configured for OTP, but has no active tokens, remove
|
||||
- * OTP from the list since the user obviously can't log in this way. */
|
||||
- if (count == 0)
|
||||
+ /*
|
||||
+ * If there are no valid tokens then we need to remove the OTP flag,
|
||||
+ * unless OTP is the only auth type allowed...
|
||||
+ */
|
||||
+ if (count == 0) {
|
||||
+ /* Remove the OTP flag for now */
|
||||
*ua &= ~IPADB_USER_AUTH_OTP;
|
||||
+
|
||||
+ if (*ua == 0) {
|
||||
+ /*
|
||||
+ * Ok, we "only" allow OTP, so if there is an expired/disabled
|
||||
+ * token then add back the OTP flag as the server will double
|
||||
+ * check the validity and reject the entire bind. Otherwise, this
|
||||
+ * is the first time the user is authenticating and the user
|
||||
+ * should be allowed to bind using its password
|
||||
+ */
|
||||
+ static const char *expired_ftmpl = "(&"
|
||||
+ "(objectClass=ipaToken)(ipatokenOwner=%s)"
|
||||
+ "(|(ipatokenNotAfter<=%s)(!(ipatokenNotAfter=*))"
|
||||
+ "(ipatokenDisabled=True))"
|
||||
+ ")";
|
||||
+ if (asprintf(&filter, expired_ftmpl, dn, datetime) < 0) {
|
||||
+ ldap_memfree(dn);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ krb5_klog_syslog(LOG_INFO,
|
||||
+ "Entry (%s) does not have a valid token and only OTP "
|
||||
+ "authentication is supported, checking for expired tokens...",
|
||||
+ dn);
|
||||
+
|
||||
+ kerr = ipadb_simple_search(ipactx, ipactx->base, LDAP_SCOPE_SUBTREE,
|
||||
+ filter, (char**) attrs, &res);
|
||||
+ free(filter);
|
||||
+ if (kerr != 0 || res == NULL) {
|
||||
+ ldap_memfree(dn);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (ldap_count_entries(ipactx->lcontext, res) > 0) {
|
||||
+ /*
|
||||
+ * Ok we only allow OTP, and there are expired/disabled tokens
|
||||
+ * so add the OTP flag back, and the server will reject the
|
||||
+ * bind
|
||||
+ */
|
||||
+ krb5_klog_syslog(LOG_INFO,
|
||||
+ "Entry (%s) does have an expired/disabled token so this "
|
||||
+ "user can not fall through to password auth", dn);
|
||||
+ *ua |= IPADB_USER_AUTH_OTP;
|
||||
+ }
|
||||
+ ldap_msgfree(res);
|
||||
+ }
|
||||
+ }
|
||||
+ ldap_memfree(dn);
|
||||
}
|
||||
|
||||
static void ipadb_validate_radius(struct ipadb_context *ipactx,
|
||||
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c
|
||||
index c967e2cfffbd920280639f3188783ec150523b47..1c1340e31ac30cb01412a7065ea339cb5461e839 100644
|
||||
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c
|
||||
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c
|
||||
@@ -1528,7 +1528,8 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
|
||||
if (!syncreq && (otpreq == OTP_IS_NOT_REQUIRED)) {
|
||||
ret = ipapwd_gen_checks(pb, &errMesg, &krbcfg, IPAPWD_CHECK_ONLY_CONFIG);
|
||||
if (ret != 0) {
|
||||
- LOG_FATAL("ipapwd_gen_checks failed!?\n");
|
||||
+ LOG_FATAL("ipapwd_gen_checks failed for '%s': %s\n",
|
||||
+ slapi_sdn_get_dn(sdn), errMesg);
|
||||
slapi_entry_free(entry);
|
||||
slapi_sdn_free(&sdn);
|
||||
return 0;
|
||||
diff --git a/ipatests/test_integration/test_otp.py b/ipatests/test_integration/test_otp.py
|
||||
index 350371bfe1e4c1cc6dcc89f6584f813fcb0d32a0..878b4fb560ba8d7768ead54b065656462545babd 100644
|
||||
--- a/ipatests/test_integration/test_otp.py
|
||||
+++ b/ipatests/test_integration/test_otp.py
|
||||
@@ -10,6 +10,7 @@ import re
|
||||
import time
|
||||
import textwrap
|
||||
from urllib.parse import urlparse, parse_qs
|
||||
+from paramiko import AuthenticationException
|
||||
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
@@ -83,7 +84,7 @@ def kinit_otp(host, user, *, password, otp, success=True):
|
||||
)
|
||||
|
||||
|
||||
-def ssh_2f(hostname, username, answers_dict, port=22):
|
||||
+def ssh_2f(hostname, username, answers_dict, port=22, unwanted_prompt=""):
|
||||
"""
|
||||
:param hostname: hostname
|
||||
:param username: username
|
||||
@@ -103,6 +104,10 @@ def ssh_2f(hostname, username, answers_dict, port=22):
|
||||
logger.info("Prompt is: '%s'", prmpt_str)
|
||||
logger.info(
|
||||
"Answer to ssh prompt is: '%s'", answers_dict[prmpt_str])
|
||||
+ if unwanted_prompt and prmpt_str == unwanted_prompt:
|
||||
+ # We should not see this prompt
|
||||
+ raise ValueError("We got an unwanted prompt: "
|
||||
+ + answers_dict[prmpt_str])
|
||||
return resp
|
||||
|
||||
import paramiko
|
||||
@@ -193,7 +198,8 @@ class TestOTPToken(IntegrationTest):
|
||||
|
||||
# skipping too many OTP fails
|
||||
otp1 = hotp.generate(10).decode("ascii")
|
||||
- kinit_otp(self.master, USER, password=PASSWORD, otp=otp1, success=False)
|
||||
+ kinit_otp(self.master, USER, password=PASSWORD, otp=otp1,
|
||||
+ success=False)
|
||||
# Now the token is desynchronized
|
||||
yield (otpuid, hotp)
|
||||
|
||||
@@ -536,3 +542,87 @@ class TestOTPToken(IntegrationTest):
|
||||
finally:
|
||||
master.run_command(['ipa', 'pwpolicy-mod', '--minlife', '1'])
|
||||
master.run_command(['ipa', 'user-del', USER1])
|
||||
+
|
||||
+ def test_totp_expired_ldap(self):
|
||||
+ master = self.master
|
||||
+ basedn = master.domain.basedn
|
||||
+ USER1 = 'user-expired-otp'
|
||||
+ TMP_PASSWORD = 'Secret1234509'
|
||||
+ binddn = DN(f"uid={USER1},cn=users,cn=accounts,{basedn}")
|
||||
+ controls = [
|
||||
+ BooleanControl(
|
||||
+ controlType="2.16.840.1.113730.3.8.10.7",
|
||||
+ booleanValue=True)
|
||||
+ ]
|
||||
+
|
||||
+ tasks.kinit_admin(master)
|
||||
+ master.run_command(['ipa', 'pwpolicy-mod', '--minlife', '0'])
|
||||
+ tasks.user_add(master, USER1, password=TMP_PASSWORD)
|
||||
+ # Enforce use of OTP token for this user
|
||||
+ master.run_command(['ipa', 'user-mod', USER1,
|
||||
+ '--user-auth-type=otp'])
|
||||
+ try:
|
||||
+ # Change initial password through the IPA endpoint
|
||||
+ url = f'https://{master.hostname}/ipa/session/change_password'
|
||||
+ master.run_command(['curl', '-d', f'user={USER1}',
|
||||
+ '-d', f'old_password={TMP_PASSWORD}',
|
||||
+ '-d', f'new_password={PASSWORD}',
|
||||
+ '--referer', f'https://{master.hostname}/ipa',
|
||||
+ url])
|
||||
+ conn = master.ldap_connect()
|
||||
+ # First, attempt authenticating with a password but without LDAP
|
||||
+ # control to enforce OTP presence and without server-side
|
||||
+ # enforcement of the OTP presence check.
|
||||
+ conn.simple_bind(binddn, f"{PASSWORD}")
|
||||
+
|
||||
+ # Add an OTP token and then modify it to be expired
|
||||
+ otpuid, totp = add_otptoken(master, USER1, otptype="totp")
|
||||
+
|
||||
+ # Make sure OTP auth is working
|
||||
+ otpvalue = totp.generate(int(time.time())).decode("ascii")
|
||||
+ conn = master.ldap_connect()
|
||||
+ conn.simple_bind(binddn, f"{PASSWORD}{otpvalue}",
|
||||
+ client_controls=controls)
|
||||
+ conn.unbind()
|
||||
+
|
||||
+ # Modfy token so that is now expired
|
||||
+ args = [
|
||||
+ "ipa",
|
||||
+ "otptoken-mod",
|
||||
+ otpuid,
|
||||
+ "--not-after",
|
||||
+ "20241001010000Z",
|
||||
+ ]
|
||||
+ master.run_command(args)
|
||||
+
|
||||
+ # Next, authenticate with Password+OTP again and with the LDAP
|
||||
+ # control this operation should now fail
|
||||
+ time.sleep(45)
|
||||
+ otpvalue = totp.generate(int(time.time())).decode("ascii")
|
||||
+
|
||||
+ conn = master.ldap_connect()
|
||||
+ with pytest.raises(errors.ACIError):
|
||||
+ conn.simple_bind(binddn, f"{PASSWORD}{otpvalue}",
|
||||
+ client_controls=controls)
|
||||
+
|
||||
+ # Sleep to make sure we are going to use a different token value
|
||||
+ time.sleep(45)
|
||||
+
|
||||
+ # Use OTP token again but authenticate over ssh and make sure it
|
||||
+ # doesn't fallthrough to asking for a password
|
||||
+ otpvalue = totp.generate(int(time.time())).decode("ascii")
|
||||
+ answers = {
|
||||
+ 'Enter first factor:': PASSWORD,
|
||||
+ 'Enter second factor:': otpvalue
|
||||
+ }
|
||||
+ with pytest.raises(AuthenticationException):
|
||||
+ # ssh should fail and NOT ask for a password
|
||||
+ ssh_2f(master.hostname, USER1, answers,
|
||||
+ unwanted_prompt="Password:")
|
||||
+
|
||||
+ # Remove token
|
||||
+ del_otptoken(self.master, otpuid)
|
||||
+
|
||||
+ finally:
|
||||
+ master.run_command(['ipa', 'pwpolicy-mod', '--minlife', '1'])
|
||||
+ master.run_command(['ipa', 'user-del', USER1])
|
||||
--
|
||||
2.46.2
|
||||
|
@ -1,139 +0,0 @@
|
||||
From 48846e98e5e988d600ddf81c937f353fcecdea1a Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Mon, 27 Nov 2023 16:11:08 -0500
|
||||
Subject: [PATCH 1/2] hbactest was not collecting or returning messages
|
||||
|
||||
hbactest does a number of internal searches, one of which
|
||||
can exceed the configured sizelimit: hbacrule-find
|
||||
|
||||
Collect any messages returned from thsi call and display them
|
||||
to the user on the cli.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9486
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
---
|
||||
ipaclient/plugins/hbactest.py | 2 ++
|
||||
ipaserver/plugins/hbactest.py | 14 +++++++++++---
|
||||
2 files changed, 13 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/ipaclient/plugins/hbactest.py b/ipaclient/plugins/hbactest.py
|
||||
index 1b54530b2..e0f93b9c2 100644
|
||||
--- a/ipaclient/plugins/hbactest.py
|
||||
+++ b/ipaclient/plugins/hbactest.py
|
||||
@@ -38,6 +38,8 @@ class hbactest(CommandOverride):
|
||||
# Note that we don't actually use --detail below to see if details need
|
||||
# to be printed as our execute() method will return None for corresponding
|
||||
# entries and None entries will be skipped.
|
||||
+ self.log_messages(output)
|
||||
+
|
||||
for o in self.output:
|
||||
if o == 'value':
|
||||
continue
|
||||
diff --git a/ipaserver/plugins/hbactest.py b/ipaserver/plugins/hbactest.py
|
||||
index 887a35b7e..568c13174 100644
|
||||
--- a/ipaserver/plugins/hbactest.py
|
||||
+++ b/ipaserver/plugins/hbactest.py
|
||||
@@ -24,6 +24,8 @@ from ipalib import Command, Str, Flag, Int
|
||||
from ipalib import _
|
||||
from ipapython.dn import DN
|
||||
from ipalib.plugable import Registry
|
||||
+from ipalib.messages import VersionMissing
|
||||
+
|
||||
if api.env.in_server:
|
||||
try:
|
||||
import ipaserver.dcerpc
|
||||
@@ -323,6 +325,9 @@ class hbactest(Command):
|
||||
# 2. Required options are (user, target host, service)
|
||||
# 3. Options: rules to test (--rules, --enabled, --disabled), request for detail output
|
||||
rules = []
|
||||
+ result = {
|
||||
+ 'warning':None, 'matched':None, 'notmatched':None, 'error':None
|
||||
+ }
|
||||
|
||||
# Use all enabled IPA rules by default
|
||||
all_enabled = True
|
||||
@@ -351,8 +356,12 @@ class hbactest(Command):
|
||||
|
||||
hbacset = []
|
||||
if len(testrules) == 0:
|
||||
- hbacset = self.api.Command.hbacrule_find(
|
||||
- sizelimit=sizelimit, no_members=False)['result']
|
||||
+ hbacrules = self.api.Command.hbacrule_find(
|
||||
+ sizelimit=sizelimit, no_members=False)
|
||||
+ hbacset = hbacrules['result']
|
||||
+ for message in hbacrules['messages']:
|
||||
+ if message['code'] != VersionMissing.errno:
|
||||
+ result.setdefault('messages', []).append(message)
|
||||
else:
|
||||
for rule in testrules:
|
||||
try:
|
||||
@@ -469,7 +478,6 @@ class hbactest(Command):
|
||||
error_rules = []
|
||||
warning_rules = []
|
||||
|
||||
- result = {'warning':None, 'matched':None, 'notmatched':None, 'error':None}
|
||||
if not options['nodetail']:
|
||||
# Validate runs rules one-by-one and reports failed ones
|
||||
for ipa_rule in rules:
|
||||
--
|
||||
2.43.0
|
||||
|
||||
|
||||
From d1e09c68af8ac77f656dd639af5d9a7f07c41f9d Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Tue, 28 Nov 2023 13:35:13 -0500
|
||||
Subject: [PATCH 2/2] ipatests: Verify that hbactest will return messages
|
||||
|
||||
Limit the sizelimit of the hbactest request to confirm that
|
||||
the output includes a SearchResultTruncated message.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9486
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
---
|
||||
ipatests/test_xmlrpc/test_hbactest_plugin.py | 19 ++++++++++++++++++-
|
||||
1 file changed, 18 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ipatests/test_xmlrpc/test_hbactest_plugin.py b/ipatests/test_xmlrpc/test_hbactest_plugin.py
|
||||
index 73c4ce232..e2e66c759 100644
|
||||
--- a/ipatests/test_xmlrpc/test_hbactest_plugin.py
|
||||
+++ b/ipatests/test_xmlrpc/test_hbactest_plugin.py
|
||||
@@ -134,6 +134,7 @@ class test_hbactest(XMLRPC_test):
|
||||
assert ret['value']
|
||||
assert ret['error'] is None
|
||||
assert ret['matched'] is None
|
||||
+ assert 'messages' not in ret
|
||||
assert ret['notmatched'] is None
|
||||
|
||||
def test_c_hbactest_check_rules_enabled_detail(self):
|
||||
@@ -200,7 +201,23 @@ class test_hbactest(XMLRPC_test):
|
||||
nodetail=True
|
||||
)
|
||||
|
||||
- def test_g_hbactest_clear_testing_data(self):
|
||||
+ def test_g_hbactest_searchlimit_message(self):
|
||||
+ """
|
||||
+ Test running 'ipa hbactest' with limited --sizelimit
|
||||
+
|
||||
+ We know there are at least 6 rules, 4 created here + 2 default.
|
||||
+ """
|
||||
+ ret = api.Command['hbactest'](
|
||||
+ user=self.test_user,
|
||||
+ targethost=self.test_host,
|
||||
+ service=self.test_service,
|
||||
+ nodetail=True,
|
||||
+ sizelimit=2,
|
||||
+ )
|
||||
+
|
||||
+ assert ret['messages'] is not None
|
||||
+
|
||||
+ def test_h_hbactest_clear_testing_data(self):
|
||||
"""
|
||||
Clear data for HBAC test plugin testing.
|
||||
"""
|
||||
--
|
||||
2.43.0
|
||||
|
41
SOURCES/0016-ipatests-Activate-ssh-in-sssd.conf.patch
Normal file
41
SOURCES/0016-ipatests-Activate-ssh-in-sssd.conf.patch
Normal file
@ -0,0 +1,41 @@
|
||||
From 761647f842567713032709753b6d63467d9871a6 Mon Sep 17 00:00:00 2001
|
||||
From: Sudhir Menon <sumenon@redhat.com>
|
||||
Date: Mon, 23 Sep 2024 14:05:43 +0530
|
||||
Subject: [PATCH] ipatests: Activate ssh in sssd.conf
|
||||
|
||||
This testcase checks that services: ssh
|
||||
is included in the sssd.conf file when
|
||||
ipa-client-install is successful.
|
||||
|
||||
Ref: https://pagure.io/freeipa/issue/9649
|
||||
|
||||
Signed-off-by: Sudhir Menon <sumenon@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipatests/test_integration/test_installation_client.py | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
diff --git a/ipatests/test_integration/test_installation_client.py b/ipatests/test_integration/test_installation_client.py
|
||||
index f8567b39eead4dffd522aad504fa72a086969257..884bff2f2f3e49f66da391424e128d8e31b82a8a 100644
|
||||
--- a/ipatests/test_integration/test_installation_client.py
|
||||
+++ b/ipatests/test_integration/test_installation_client.py
|
||||
@@ -94,6 +94,16 @@ class TestInstallClient(IntegrationTest):
|
||||
).encode() not in krb5_cfg
|
||||
tasks.uninstall_client(self.clients[0])
|
||||
|
||||
+ def test_check_ssh_service_is_activated(self):
|
||||
+ """
|
||||
+ This test checks all default services are activated
|
||||
+ in sssd.conf including ssh
|
||||
+ """
|
||||
+ tasks.install_client(self.master, self.clients[0])
|
||||
+ sssd_cfg = self.clients[0].get_file_contents(paths.SSSD_CONF)
|
||||
+ assert 'services = nss, pam, ssh, sudo' in sssd_cfg.decode()
|
||||
+ tasks.uninstall_client(self.clients[0])
|
||||
+
|
||||
def test_install_with_automount(self):
|
||||
"""Test that installation with automount is successful"""
|
||||
tasks.install_client(self.master, self.clients[0],
|
||||
--
|
||||
2.46.2
|
||||
|
@ -1,43 +0,0 @@
|
||||
From 16a739e0260f97705827f972d53c828809dbfdb2 Mon Sep 17 00:00:00 2001
|
||||
From: Masahiro Matsuya <mmatsuya@redhat.com>
|
||||
Date: Tue, 9 Jan 2024 23:12:11 +0900
|
||||
Subject: [PATCH] ipatests: wait for replica update in test_dns_locations
|
||||
|
||||
test_ipa_ca_records and test_adtrust_system_records can fail with
|
||||
NXDOMAIN, because it doesn't wait enough for the update on replica.
|
||||
It can be resolved by waiting for the update with wait_for_replication.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9504
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
(cherry picked from commit 905a55a4ef926068630ebd2ab375f58c24dedcd1)
|
||||
---
|
||||
ipatests/test_integration/test_dns_locations.py | 6 ++++++
|
||||
1 file changed, 6 insertions(+)
|
||||
|
||||
diff --git a/ipatests/test_integration/test_dns_locations.py b/ipatests/test_integration/test_dns_locations.py
|
||||
index 44900af80..89a310892 100644
|
||||
--- a/ipatests/test_integration/test_dns_locations.py
|
||||
+++ b/ipatests/test_integration/test_dns_locations.py
|
||||
@@ -534,6 +534,9 @@ class TestDNSLocations(IntegrationTest):
|
||||
|
||||
expected_servers = (self.master.ip, self.replicas[1].ip)
|
||||
|
||||
+ ldap = self.master.ldap_connect()
|
||||
+ tasks.wait_for_replication(ldap)
|
||||
+
|
||||
for ip in (self.master.ip, self.replicas[0].ip, self.replicas[1].ip):
|
||||
self._test_A_rec_against_server(ip, self.domain, expected_servers)
|
||||
|
||||
@@ -557,6 +560,9 @@ class TestDNSLocations(IntegrationTest):
|
||||
(self.PRIO_HIGH, self.WEIGHT, DNSName(self.master.hostname)),
|
||||
)
|
||||
|
||||
+ ldap = self.master.ldap_connect()
|
||||
+ tasks.wait_for_replication(ldap)
|
||||
+
|
||||
for ip in (self.master.ip, self.replicas[0].ip, self.replicas[1].ip):
|
||||
self._test_SRV_rec_against_server(
|
||||
ip, self.domain, expected_servers,
|
||||
--
|
||||
2.43.0
|
||||
|
@ -1,707 +0,0 @@
|
||||
From c3ac69e9cf8dfcc31ed11fc988c37bd99d3ec3cf Mon Sep 17 00:00:00 2001
|
||||
From: Julien Rische <jrische@redhat.com>
|
||||
Date: Wed, 14 Feb 2024 17:47:00 +0100
|
||||
Subject: [PATCH] ipa-kdb: Rework ipadb_reinit_mspac()
|
||||
|
||||
Modify ipadb_reinit_mspac() to allocate and initialize ipactx->mspac
|
||||
only if all its attributes can be set. If not, ipactx->mspac is set to
|
||||
NULL. This makes easier to determine if the KDC is able to generate PACs
|
||||
or not.
|
||||
|
||||
Also ipadb_reinit_mspac() is now able to return a status message
|
||||
explaining why initialization of the PAC generator failed. This message
|
||||
is printed in KDC logs.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9535
|
||||
|
||||
Signed-off-by: Julien Rische <jrische@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abbra@users.noreply.github.com>
|
||||
(cherry picked from commit 7f072e348d318e928f6270a182ca04dee8716677)
|
||||
---
|
||||
daemons/ipa-kdb/ipa_kdb.c | 14 +-
|
||||
daemons/ipa-kdb/ipa_kdb.h | 4 +-
|
||||
daemons/ipa-kdb/ipa_kdb_mspac.c | 340 +++++++++++++-----------
|
||||
daemons/ipa-kdb/ipa_kdb_mspac_private.h | 2 +-
|
||||
daemons/ipa-kdb/ipa_kdb_mspac_v6.c | 5 +-
|
||||
daemons/ipa-kdb/ipa_kdb_mspac_v9.c | 16 +-
|
||||
daemons/ipa-kdb/ipa_kdb_principals.c | 6 +-
|
||||
7 files changed, 218 insertions(+), 169 deletions(-)
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c
|
||||
index 0c6325df9..fcadb8ee7 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb.c
|
||||
@@ -443,6 +443,7 @@ int ipadb_get_connection(struct ipadb_context *ipactx)
|
||||
struct timeval tv = { 5, 0 };
|
||||
LDAPMessage *res = NULL;
|
||||
LDAPMessage *first;
|
||||
+ const char *stmsg;
|
||||
int ret;
|
||||
int v3;
|
||||
|
||||
@@ -522,16 +523,9 @@ int ipadb_get_connection(struct ipadb_context *ipactx)
|
||||
}
|
||||
|
||||
/* get adtrust options using default refresh interval */
|
||||
- ret = ipadb_reinit_mspac(ipactx, false);
|
||||
- if (ret && ret != ENOENT) {
|
||||
- /* TODO: log that there is an issue with adtrust settings */
|
||||
- if (ipactx->lcontext == NULL) {
|
||||
- /* for some reason ldap connection was reset in ipadb_reinit_mspac
|
||||
- * and is no longer established => failure of ipadb_get_connection
|
||||
- */
|
||||
- goto done;
|
||||
- }
|
||||
- }
|
||||
+ ret = ipadb_reinit_mspac(ipactx, false, &stmsg);
|
||||
+ if (ret && stmsg)
|
||||
+ krb5_klog_syslog(LOG_WARNING, "MS-PAC generator: %s", stmsg);
|
||||
|
||||
ret = 0;
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
|
||||
index 5de5ea7a5..7baf4697f 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb.h
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb.h
|
||||
@@ -352,7 +352,9 @@ krb5_error_code ipadb_v9_issue_pac(krb5_context context, unsigned int flags,
|
||||
krb5_data ***auth_indicators);
|
||||
#endif
|
||||
|
||||
-krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_reinit);
|
||||
+krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx,
|
||||
+ bool force_reinit,
|
||||
+ const char **stmsg);
|
||||
|
||||
void ipadb_mspac_struct_free(struct ipadb_mspac **mspac);
|
||||
krb5_error_code ipadb_check_transited_realms(krb5_context kcontext,
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
index 886ed7785..deed513b9 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
@@ -793,16 +793,16 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ if (!ipactx->mspac) {
|
||||
+ /* can't give a PAC without server NetBIOS name or primary group RID */
|
||||
+ return ENOENT;
|
||||
+ }
|
||||
+
|
||||
if (info3->base.primary_gid == 0) {
|
||||
if (is_host || is_service) {
|
||||
info3->base.primary_gid = 515; /* Well known RID for domain computers group */
|
||||
} else {
|
||||
- if (ipactx->mspac->fallback_rid) {
|
||||
- info3->base.primary_gid = ipactx->mspac->fallback_rid;
|
||||
- } else {
|
||||
- /* can't give a pack without a primary group rid */
|
||||
- return ENOENT;
|
||||
- }
|
||||
+ info3->base.primary_gid = ipactx->mspac->fallback_rid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -812,26 +812,16 @@ static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
|
||||
/* always zero out, not used for Krb, only NTLM */
|
||||
memset(&info3->base.key, '\0', sizeof(info3->base.key));
|
||||
|
||||
- if (ipactx->mspac->flat_server_name) {
|
||||
- info3->base.logon_server.string =
|
||||
- talloc_strdup(memctx, ipactx->mspac->flat_server_name);
|
||||
- if (!info3->base.logon_server.string) {
|
||||
- return ENOMEM;
|
||||
- }
|
||||
- } else {
|
||||
- /* can't give a pack without Server NetBIOS Name :-| */
|
||||
- return ENOENT;
|
||||
+ info3->base.logon_server.string =
|
||||
+ talloc_strdup(memctx, ipactx->mspac->flat_server_name);
|
||||
+ if (!info3->base.logon_server.string) {
|
||||
+ return ENOMEM;
|
||||
}
|
||||
|
||||
- if (ipactx->mspac->flat_domain_name) {
|
||||
- info3->base.logon_domain.string =
|
||||
- talloc_strdup(memctx, ipactx->mspac->flat_domain_name);
|
||||
- if (!info3->base.logon_domain.string) {
|
||||
- return ENOMEM;
|
||||
- }
|
||||
- } else {
|
||||
- /* can't give a pack without Domain NetBIOS Name :-| */
|
||||
- return ENOENT;
|
||||
+ info3->base.logon_domain.string =
|
||||
+ talloc_strdup(memctx, ipactx->mspac->flat_domain_name);
|
||||
+ if (!info3->base.logon_domain.string) {
|
||||
+ return ENOMEM;
|
||||
}
|
||||
|
||||
if (is_host || is_service) {
|
||||
@@ -1044,6 +1034,11 @@ krb5_error_code ipadb_get_pac(krb5_context kcontext,
|
||||
return KRB5_KDB_DBNOTINITED;
|
||||
}
|
||||
|
||||
+ /* Check if PAC generator is initialized */
|
||||
+ if (!ipactx->mspac) {
|
||||
+ return ENOENT;
|
||||
+ }
|
||||
+
|
||||
ied = (struct ipadb_e_data *)client->e_data;
|
||||
if (ied->magic != IPA_E_DATA_MAGIC) {
|
||||
return EINVAL;
|
||||
@@ -1626,14 +1621,14 @@ static struct ipadb_adtrusts *get_domain_from_realm(krb5_context context,
|
||||
{
|
||||
struct ipadb_context *ipactx;
|
||||
struct ipadb_adtrusts *domain;
|
||||
- int i;
|
||||
+ size_t i;
|
||||
|
||||
ipactx = ipadb_get_context(context);
|
||||
if (!ipactx) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
- if (ipactx->mspac == NULL) {
|
||||
+ if (!ipactx->mspac) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1655,6 +1650,7 @@ static struct ipadb_adtrusts *get_domain_from_realm_update(krb5_context context,
|
||||
{
|
||||
struct ipadb_context *ipactx;
|
||||
struct ipadb_adtrusts *domain;
|
||||
+ const char *stmsg = NULL;
|
||||
krb5_error_code kerr;
|
||||
|
||||
ipactx = ipadb_get_context(context);
|
||||
@@ -1663,8 +1659,10 @@ static struct ipadb_adtrusts *get_domain_from_realm_update(krb5_context context,
|
||||
}
|
||||
|
||||
/* re-init MS-PAC info using default update interval */
|
||||
- kerr = ipadb_reinit_mspac(ipactx, false);
|
||||
+ kerr = ipadb_reinit_mspac(ipactx, false, &stmsg);
|
||||
if (kerr != 0) {
|
||||
+ if (stmsg)
|
||||
+ krb5_klog_syslog(LOG_WARNING, "MS-PAC generator: %s", stmsg);
|
||||
return NULL;
|
||||
}
|
||||
domain = get_domain_from_realm(context, realm);
|
||||
@@ -1717,6 +1715,7 @@ static krb5_error_code check_logon_info_consistent(krb5_context context,
|
||||
struct ipadb_e_data *ied = NULL;
|
||||
int flags = 0;
|
||||
struct dom_sid client_sid;
|
||||
+ const char *stmsg = NULL;
|
||||
#ifdef KRB5_KDB_FLAG_ALIAS_OK
|
||||
flags = KRB5_KDB_FLAG_ALIAS_OK;
|
||||
#endif
|
||||
@@ -1730,10 +1729,14 @@ static krb5_error_code check_logon_info_consistent(krb5_context context,
|
||||
* check that our own view on the PAC details is up to date */
|
||||
if (ipactx->mspac->domsid.num_auths == 0) {
|
||||
/* Force re-init of KDB's view on our domain */
|
||||
- kerr = ipadb_reinit_mspac(ipactx, true);
|
||||
+ kerr = ipadb_reinit_mspac(ipactx, true, &stmsg);
|
||||
if (kerr != 0) {
|
||||
- krb5_klog_syslog(LOG_ERR,
|
||||
- "PAC issue: unable to update realm's view on PAC info");
|
||||
+ if (stmsg) {
|
||||
+ krb5_klog_syslog(LOG_ERR, "MS-PAC generator: %s", stmsg);
|
||||
+ } else {
|
||||
+ krb5_klog_syslog(LOG_ERR, "PAC issue: unable to update " \
|
||||
+ "realm's view on PAC info");
|
||||
+ }
|
||||
return KRB5KDC_ERR_POLICY;
|
||||
}
|
||||
}
|
||||
@@ -1746,7 +1749,7 @@ static krb5_error_code check_logon_info_consistent(krb5_context context,
|
||||
if (is_s4u && (ipactx->mspac->trusts != NULL)) {
|
||||
/* Iterate through list of trusts and check if this SID belongs to
|
||||
* one of the domains we trust */
|
||||
- for(int i = 0 ; i < ipactx->mspac->num_trusts ; i++) {
|
||||
+ for(size_t i = 0 ; i < ipactx->mspac->num_trusts ; i++) {
|
||||
result = dom_sid_check(&ipactx->mspac->trusts[i].domsid,
|
||||
info->info->info3.base.domain_sid, true);
|
||||
if (result) {
|
||||
@@ -1858,11 +1861,11 @@ krb5_error_code filter_logon_info(krb5_context context,
|
||||
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,
|
||||
+ for (size_t m = 0; m < mspac_ctx->num_trusts; m++) {
|
||||
+ result = dom_sid_check(&mspac_ctx->trusts[m].domsid,
|
||||
info->info->info3.base.domain_sid, true);
|
||||
if (result) {
|
||||
- domain = &mspac_ctx->trusts[k];
|
||||
+ domain = &mspac_ctx->trusts[m];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2091,10 +2094,10 @@ static krb5_error_code ipadb_check_logon_info(krb5_context context,
|
||||
return KRB5_KDB_DBNOTINITED;
|
||||
}
|
||||
/* In S4U case we might be dealing with the PAC issued by the trusted domain */
|
||||
- if ((ipactx->mspac->trusts != NULL)) {
|
||||
+ if (ipactx->mspac->trusts) {
|
||||
/* Iterate through list of trusts and check if this SID belongs to
|
||||
* one of the domains we trust */
|
||||
- for(int i = 0 ; i < ipactx->mspac->num_trusts ; i++) {
|
||||
+ for(size_t i = 0 ; i < ipactx->mspac->num_trusts ; i++) {
|
||||
result = dom_sid_check(&ipactx->mspac->trusts[i].domsid,
|
||||
&client_sid, false);
|
||||
if (result) {
|
||||
@@ -2631,7 +2634,7 @@ static char *get_server_netbios_name(struct ipadb_context *ipactx)
|
||||
|
||||
void ipadb_mspac_struct_free(struct ipadb_mspac **mspac)
|
||||
{
|
||||
- int i, j;
|
||||
+ size_t i, j;
|
||||
|
||||
if (!*mspac) return;
|
||||
|
||||
@@ -2786,7 +2789,8 @@ ipadb_mspac_get_trusted_domains(struct ipadb_context *ipactx)
|
||||
LDAPDN dn = NULL;
|
||||
char **sid_blocklist_incoming = NULL;
|
||||
char **sid_blocklist_outgoing = NULL;
|
||||
- int ret, n, i;
|
||||
+ size_t i, n;
|
||||
+ int ret;
|
||||
|
||||
ret = asprintf(&base, "cn=ad,cn=trusts,%s", ipactx->base);
|
||||
if (ret == -1) {
|
||||
@@ -2871,7 +2875,7 @@ ipadb_mspac_get_trusted_domains(struct ipadb_context *ipactx)
|
||||
|
||||
t[n].upn_suffixes_len = NULL;
|
||||
if (t[n].upn_suffixes != NULL) {
|
||||
- int len = 0;
|
||||
+ size_t len = 0;
|
||||
|
||||
for (; t[n].upn_suffixes[len] != NULL; len++);
|
||||
|
||||
@@ -2986,108 +2990,114 @@ done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
-krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_reinit)
|
||||
+krb5_error_code
|
||||
+ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_reinit,
|
||||
+ const char **stmsg)
|
||||
{
|
||||
char *dom_attrs[] = { "ipaNTFlatName",
|
||||
"ipaNTFallbackPrimaryGroup",
|
||||
"ipaNTSecurityIdentifier",
|
||||
NULL };
|
||||
char *grp_attrs[] = { "ipaNTSecurityIdentifier", NULL };
|
||||
- krb5_error_code kerr;
|
||||
LDAPMessage *result = NULL;
|
||||
LDAPMessage *lentry;
|
||||
- struct dom_sid gsid;
|
||||
- char *resstr;
|
||||
- int ret;
|
||||
+ struct dom_sid gsid, domsid;
|
||||
+ char *resstr = NULL;
|
||||
+ char *flat_domain_name = NULL;
|
||||
+ char *flat_server_name = NULL;
|
||||
+ char *fallback_group = NULL;
|
||||
+ uint32_t fallback_rid;
|
||||
time_t now;
|
||||
+ const char *in_stmsg = NULL;
|
||||
+ int err;
|
||||
+ krb5_error_code trust_kerr = 0;
|
||||
+
|
||||
|
||||
/* Do not update the mspac struct more than once a minute. This would
|
||||
* avoid heavy load on the directory server if there are lots of requests
|
||||
* from domains which we do not trust. */
|
||||
now = time(NULL);
|
||||
|
||||
- if (ipactx->mspac != NULL &&
|
||||
- (force_reinit == false) &&
|
||||
- (now > ipactx->mspac->last_update) &&
|
||||
- (now - ipactx->mspac->last_update) < 60) {
|
||||
- return 0;
|
||||
- }
|
||||
-
|
||||
- if (ipactx->mspac && ipactx->mspac->num_trusts == 0) {
|
||||
- /* Check if there is any trust configured. If not, just return
|
||||
- * and do not re-initialize the MS-PAC structure. */
|
||||
- kerr = ipadb_mspac_check_trusted_domains(ipactx);
|
||||
- if (kerr == KRB5_KDB_NOENTRY) {
|
||||
- kerr = 0;
|
||||
- goto done;
|
||||
- } else if (kerr != 0) {
|
||||
- goto done;
|
||||
+ if (ipactx->mspac) {
|
||||
+ if (!force_reinit &&
|
||||
+ (now > ipactx->mspac->last_update) &&
|
||||
+ (now - ipactx->mspac->last_update) < 60) {
|
||||
+ /* SKIP */
|
||||
+ err = 0;
|
||||
+ goto end;
|
||||
}
|
||||
- }
|
||||
-
|
||||
- /* clean up in case we had old values around */
|
||||
- ipadb_mspac_struct_free(&ipactx->mspac);
|
||||
|
||||
- ipactx->mspac = calloc(1, sizeof(struct ipadb_mspac));
|
||||
- if (!ipactx->mspac) {
|
||||
- kerr = ENOMEM;
|
||||
- goto done;
|
||||
+ if (ipactx->mspac->num_trusts == 0) {
|
||||
+ /* Check if there is any trust configured. If not, just return
|
||||
+ * and do not re-initialize the MS-PAC structure. */
|
||||
+ err = ipadb_mspac_check_trusted_domains(ipactx);
|
||||
+ if (err) {
|
||||
+ if (err == KRB5_KDB_NOENTRY) {
|
||||
+ /* SKIP */
|
||||
+ err = 0;
|
||||
+ } else {
|
||||
+ in_stmsg = "Failed to fetch trusted domains information";
|
||||
+ }
|
||||
+ goto end;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
- ipactx->mspac->last_update = now;
|
||||
-
|
||||
- kerr = ipadb_simple_search(ipactx, ipactx->base, LDAP_SCOPE_SUBTREE,
|
||||
- "(objectclass=ipaNTDomainAttrs)", dom_attrs,
|
||||
- &result);
|
||||
- if (kerr == KRB5_KDB_NOENTRY) {
|
||||
- return ENOENT;
|
||||
- } else if (kerr != 0) {
|
||||
- return EIO;
|
||||
+ err = ipadb_simple_search(ipactx, ipactx->base, LDAP_SCOPE_SUBTREE,
|
||||
+ "(objectclass=ipaNTDomainAttrs)", dom_attrs,
|
||||
+ &result);
|
||||
+ if (err == KRB5_KDB_NOENTRY) {
|
||||
+ err = ENOENT;
|
||||
+ in_stmsg = "Local domain NT attributes not configured";
|
||||
+ goto end;
|
||||
+ } else if (err) {
|
||||
+ err = EIO;
|
||||
+ in_stmsg = "Failed to fetch local domain NT attributes";
|
||||
+ goto end;
|
||||
}
|
||||
|
||||
lentry = ldap_first_entry(ipactx->lcontext, result);
|
||||
if (!lentry) {
|
||||
- kerr = ENOENT;
|
||||
- goto done;
|
||||
+ err = ENOENT;
|
||||
+ in_stmsg = "Local domain NT attributes not configured";
|
||||
+ goto end;
|
||||
}
|
||||
|
||||
- ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
|
||||
- "ipaNTFlatName",
|
||||
- &ipactx->mspac->flat_domain_name);
|
||||
- if (ret) {
|
||||
- kerr = ret;
|
||||
- goto done;
|
||||
+ err = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry, "ipaNTFlatName",
|
||||
+ &flat_domain_name);
|
||||
+ if (err) {
|
||||
+ in_stmsg = "Local domain NT flat name not configured";
|
||||
+ goto end;
|
||||
}
|
||||
|
||||
- ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
|
||||
- "ipaNTSecurityIdentifier",
|
||||
- &resstr);
|
||||
- if (ret) {
|
||||
- kerr = ret;
|
||||
- goto done;
|
||||
+ err = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
|
||||
+ "ipaNTSecurityIdentifier", &resstr);
|
||||
+ if (err) {
|
||||
+ in_stmsg = "Local domain SID not configured";
|
||||
+ goto end;
|
||||
}
|
||||
|
||||
- ret = ipadb_string_to_sid(resstr, &ipactx->mspac->domsid);
|
||||
- if (ret) {
|
||||
- kerr = ret;
|
||||
- free(resstr);
|
||||
- goto done;
|
||||
+ err = ipadb_string_to_sid(resstr, &domsid);
|
||||
+ if (err) {
|
||||
+ in_stmsg = "Malformed local domain SID";
|
||||
+ goto end;
|
||||
}
|
||||
+
|
||||
free(resstr);
|
||||
|
||||
- free(ipactx->mspac->flat_server_name);
|
||||
- ipactx->mspac->flat_server_name = get_server_netbios_name(ipactx);
|
||||
- if (!ipactx->mspac->flat_server_name) {
|
||||
- kerr = ENOMEM;
|
||||
- goto done;
|
||||
+ flat_server_name = get_server_netbios_name(ipactx);
|
||||
+ if (!flat_server_name) {
|
||||
+ err = ENOMEM;
|
||||
+ goto end;
|
||||
}
|
||||
|
||||
- ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
|
||||
- "ipaNTFallbackPrimaryGroup",
|
||||
- &ipactx->mspac->fallback_group);
|
||||
- if (ret && ret != ENOENT) {
|
||||
- kerr = ret;
|
||||
- goto done;
|
||||
+ err = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
|
||||
+ "ipaNTFallbackPrimaryGroup", &fallback_group);
|
||||
+ if (err) {
|
||||
+ in_stmsg = (err == ENOENT)
|
||||
+ ? "Local fallback primary group not configured"
|
||||
+ : "Failed to fetch local fallback primary group";
|
||||
+ goto end;
|
||||
}
|
||||
|
||||
/* result and lentry not valid any more from here on */
|
||||
@@ -3095,53 +3105,81 @@ krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_rein
|
||||
result = NULL;
|
||||
lentry = NULL;
|
||||
|
||||
- if (ret != ENOENT) {
|
||||
- kerr = ipadb_simple_search(ipactx, ipactx->mspac->fallback_group,
|
||||
- LDAP_SCOPE_BASE,
|
||||
- "(objectclass=posixGroup)",
|
||||
- grp_attrs, &result);
|
||||
- if (kerr && kerr != KRB5_KDB_NOENTRY) {
|
||||
- kerr = ret;
|
||||
- goto done;
|
||||
- }
|
||||
+ err = ipadb_simple_search(ipactx, fallback_group, LDAP_SCOPE_BASE,
|
||||
+ "(objectclass=posixGroup)", grp_attrs, &result);
|
||||
+ if (err) {
|
||||
+ in_stmsg = (err == KRB5_KDB_NOENTRY)
|
||||
+ ? "Local fallback primary group has no POSIX definition"
|
||||
+ : "Failed to fetch SID of POSIX group mapped as local fallback " \
|
||||
+ "primary group";
|
||||
+ goto end;
|
||||
+ }
|
||||
|
||||
- lentry = ldap_first_entry(ipactx->lcontext, result);
|
||||
- if (!lentry) {
|
||||
- kerr = ENOENT;
|
||||
- goto done;
|
||||
- }
|
||||
+ lentry = ldap_first_entry(ipactx->lcontext, result);
|
||||
+ if (!lentry) {
|
||||
+ err = ENOENT;
|
||||
+ goto end;
|
||||
+ }
|
||||
|
||||
- if (kerr == 0) {
|
||||
- ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
|
||||
- "ipaNTSecurityIdentifier",
|
||||
- &resstr);
|
||||
- if (ret && ret != ENOENT) {
|
||||
- kerr = ret;
|
||||
- goto done;
|
||||
- }
|
||||
- if (ret == 0) {
|
||||
- ret = ipadb_string_to_sid(resstr, &gsid);
|
||||
- if (ret) {
|
||||
- free(resstr);
|
||||
- kerr = ret;
|
||||
- goto done;
|
||||
- }
|
||||
- ret = sid_split_rid(&gsid, &ipactx->mspac->fallback_rid);
|
||||
- if (ret) {
|
||||
- free(resstr);
|
||||
- kerr = ret;
|
||||
- goto done;
|
||||
- }
|
||||
- free(resstr);
|
||||
- }
|
||||
- }
|
||||
+ err = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
|
||||
+ "ipaNTSecurityIdentifier", &resstr);
|
||||
+ if (err) {
|
||||
+ in_stmsg = (err == ENOENT)
|
||||
+ ? "The POSIX group set as fallback primary group has no SID " \
|
||||
+ "configured"
|
||||
+ : "Failed to fetch SID of POSIX group set as local fallback " \
|
||||
+ "primary group";
|
||||
+ goto end;
|
||||
}
|
||||
|
||||
- kerr = ipadb_mspac_get_trusted_domains(ipactx);
|
||||
+ err = ipadb_string_to_sid(resstr, &gsid);
|
||||
+ if (err) {
|
||||
+ in_stmsg = "Malformed SID of POSIX group set as local fallback " \
|
||||
+ "primary group";
|
||||
+ goto end;
|
||||
+ }
|
||||
|
||||
-done:
|
||||
+ err = sid_split_rid(&gsid, &fallback_rid);
|
||||
+ if (err) {
|
||||
+ in_stmsg = "Malformed SID of POSIX group mapped as local fallback " \
|
||||
+ "primary group";
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ /* clean up in case we had old values around */
|
||||
+ ipadb_mspac_struct_free(&ipactx->mspac);
|
||||
+
|
||||
+ ipactx->mspac = calloc(1, sizeof(struct ipadb_mspac));
|
||||
+ if (!ipactx->mspac) {
|
||||
+ err = ENOMEM;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ ipactx->mspac->last_update = now;
|
||||
+ ipactx->mspac->flat_domain_name = flat_domain_name;
|
||||
+ ipactx->mspac->flat_server_name = flat_server_name;
|
||||
+ ipactx->mspac->domsid = domsid;
|
||||
+ ipactx->mspac->fallback_group = fallback_group;
|
||||
+ ipactx->mspac->fallback_rid = fallback_rid;
|
||||
+
|
||||
+ trust_kerr = ipadb_mspac_get_trusted_domains(ipactx);
|
||||
+ if (trust_kerr)
|
||||
+ in_stmsg = "Failed to assemble trusted domains information";
|
||||
+
|
||||
+end:
|
||||
+ if (stmsg)
|
||||
+ *stmsg = in_stmsg;
|
||||
+
|
||||
+ if (resstr) free(resstr);
|
||||
ldap_msgfree(result);
|
||||
- return kerr;
|
||||
+
|
||||
+ if (err) {
|
||||
+ if (flat_domain_name) free(flat_domain_name);
|
||||
+ if (flat_server_name) free(flat_server_name);
|
||||
+ if (fallback_group) free(fallback_group);
|
||||
+ }
|
||||
+
|
||||
+ return err ? (krb5_error_code)err : trust_kerr;
|
||||
}
|
||||
|
||||
krb5_error_code ipadb_check_transited_realms(krb5_context kcontext,
|
||||
@@ -3151,11 +3189,11 @@ krb5_error_code ipadb_check_transited_realms(krb5_context kcontext,
|
||||
{
|
||||
struct ipadb_context *ipactx;
|
||||
bool has_transited_contents, has_client_realm, has_server_realm;
|
||||
- int i;
|
||||
+ size_t i;
|
||||
krb5_error_code ret;
|
||||
|
||||
ipactx = ipadb_get_context(kcontext);
|
||||
- if (!ipactx || !ipactx->mspac) {
|
||||
+ if (!ipactx) {
|
||||
return KRB5_KDB_DBNOTINITED;
|
||||
}
|
||||
|
||||
@@ -3217,7 +3255,7 @@ krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
|
||||
char **trusted_realm)
|
||||
{
|
||||
struct ipadb_context *ipactx;
|
||||
- int i, j, length;
|
||||
+ size_t i, j, length;
|
||||
const char *name;
|
||||
bool result = false;
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac_private.h b/daemons/ipa-kdb/ipa_kdb_mspac_private.h
|
||||
index 7f0ca7a79..e650cfa73 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_mspac_private.h
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_mspac_private.h
|
||||
@@ -31,7 +31,7 @@ struct ipadb_mspac {
|
||||
char *fallback_group;
|
||||
uint32_t fallback_rid;
|
||||
|
||||
- int num_trusts;
|
||||
+ size_t num_trusts;
|
||||
struct ipadb_adtrusts *trusts;
|
||||
time_t last_update;
|
||||
};
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac_v6.c b/daemons/ipa-kdb/ipa_kdb_mspac_v6.c
|
||||
index faf47ad1b..96cd50e4c 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_mspac_v6.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_mspac_v6.c
|
||||
@@ -233,6 +233,7 @@ krb5_error_code ipadb_sign_authdata(krb5_context context,
|
||||
krb5_db_entry *client_entry = NULL;
|
||||
krb5_boolean is_equal;
|
||||
bool force_reinit_mspac = false;
|
||||
+ const char *stmsg = NULL;
|
||||
|
||||
|
||||
is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) != 0);
|
||||
@@ -309,7 +310,9 @@ krb5_error_code ipadb_sign_authdata(krb5_context context,
|
||||
force_reinit_mspac = true;
|
||||
}
|
||||
|
||||
- (void)ipadb_reinit_mspac(ipactx, force_reinit_mspac);
|
||||
+ kerr = ipadb_reinit_mspac(ipactx, force_reinit_mspac, &stmsg);
|
||||
+ if (kerr && stmsg)
|
||||
+ krb5_klog_syslog(LOG_WARNING, "MS-PAC generator: %s", stmsg);
|
||||
|
||||
kerr = ipadb_get_pac(context, flags, client, server, NULL, authtime, &pac);
|
||||
if (kerr != 0 && kerr != ENOENT) {
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac_v9.c b/daemons/ipa-kdb/ipa_kdb_mspac_v9.c
|
||||
index 3badd5b08..60db048e1 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_mspac_v9.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_mspac_v9.c
|
||||
@@ -46,6 +46,7 @@ ipadb_v9_issue_pac(krb5_context context, unsigned int flags,
|
||||
bool with_pad;
|
||||
krb5_error_code kerr = 0;
|
||||
bool is_as_req = flags & CLIENT_REFERRALS_FLAGS;
|
||||
+ const char *stmsg = NULL;
|
||||
|
||||
if (is_as_req) {
|
||||
get_authz_data_types(context, client, &with_pac, &with_pad);
|
||||
@@ -110,12 +111,19 @@ ipadb_v9_issue_pac(krb5_context context, unsigned int flags,
|
||||
force_reinit_mspac = TRUE;
|
||||
}
|
||||
}
|
||||
- (void)ipadb_reinit_mspac(ipactx, force_reinit_mspac);
|
||||
|
||||
- /* MS-PAC needs proper configuration and if it is missing, we simply skip issuing one */
|
||||
- if (ipactx->mspac->flat_server_name == NULL) {
|
||||
+ /* MS-PAC generator has to be initalized */
|
||||
+ kerr = ipadb_reinit_mspac(ipactx, force_reinit_mspac, &stmsg);
|
||||
+ if (kerr && stmsg)
|
||||
+ krb5_klog_syslog(LOG_ERR, "MS-PAC generator: %s", stmsg);
|
||||
+
|
||||
+ /* Continue even if initilization of PAC generator failed.
|
||||
+ * It may caused by the trust objects part only. */
|
||||
+
|
||||
+ /* At least the core part of the PAC generator is required. */
|
||||
+ if (!ipactx->mspac)
|
||||
return KRB5_PLUGIN_OP_NOTSUPP;
|
||||
- }
|
||||
+
|
||||
kerr = ipadb_get_pac(context, flags,
|
||||
client, server, replaced_reply_key,
|
||||
authtime, &new_pac);
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c
|
||||
index fadb132ed..07cc87746 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_principals.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_principals.c
|
||||
@@ -1495,6 +1495,7 @@ static krb5_error_code dbget_alias(krb5_context kcontext,
|
||||
krb5_db_entry *kentry = NULL;
|
||||
krb5_data *realm;
|
||||
krb5_boolean check = FALSE;
|
||||
+ const char *stmsg = NULL;
|
||||
|
||||
/* TODO: also support hostbased aliases */
|
||||
|
||||
@@ -1562,8 +1563,11 @@ static krb5_error_code dbget_alias(krb5_context kcontext,
|
||||
if (kerr == KRB5_KDB_NOENTRY) {
|
||||
/* If no trusted realm found, refresh trusted domain data and try again
|
||||
* because it might be a freshly added trust to AD */
|
||||
- kerr = ipadb_reinit_mspac(ipactx, false);
|
||||
+ kerr = ipadb_reinit_mspac(ipactx, false, &stmsg);
|
||||
if (kerr != 0) {
|
||||
+ if (stmsg)
|
||||
+ krb5_klog_syslog(LOG_WARNING, "MS-PAC generator: %s",
|
||||
+ stmsg);
|
||||
kerr = KRB5_KDB_NOENTRY;
|
||||
goto done;
|
||||
}
|
||||
--
|
||||
2.43.0
|
||||
|
131
SOURCES/0017-ipa-migrate-man-page-fix-typos-and-errors.patch
Normal file
131
SOURCES/0017-ipa-migrate-man-page-fix-typos-and-errors.patch
Normal file
@ -0,0 +1,131 @@
|
||||
From f978fa05e3ed9d4ad9d20493c05c77fb9b4976a7 Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Tue, 15 Oct 2024 17:04:55 +0200
|
||||
Subject: [PATCH] ipa-migrate man page: fix typos and errors
|
||||
|
||||
ipa-migrate man page mentions non-existing option --hostname.
|
||||
Fix the SYNOPSIS and various typos.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9681
|
||||
|
||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Mark Reynolds <mreynolds@redhat.com>
|
||||
---
|
||||
install/tools/man/ipa-migrate.1 | 38 +++++++++++++++------------------
|
||||
1 file changed, 17 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/install/tools/man/ipa-migrate.1 b/install/tools/man/ipa-migrate.1
|
||||
index 47ae47ea4afa3a5a6fe25dd9bbd14c27ab5f1fdb..5106f4f0f5b5928909ccd5abcef3bb6d1586f5df 100644
|
||||
--- a/install/tools/man/ipa-migrate.1
|
||||
+++ b/install/tools/man/ipa-migrate.1
|
||||
@@ -5,11 +5,11 @@
|
||||
.SH "NAME"
|
||||
ipa\-migrate \- Migrate an IPA server from one machine to another
|
||||
.SH "SYNOPSIS"
|
||||
-ipa\-migrate
|
||||
+\fBipa\-migrate\fR [OPTIONS] \fBprod\-mode\fR|\fBstage\-mode\fR \fIhostname\fR
|
||||
.SH "DESCRIPTION"
|
||||
|
||||
Use the \fIipa-migrate\fR command to migrate one
|
||||
-IPA server to an existing local IPA server installation.
|
||||
+IPA server \fIhostname\fR to an existing local IPA server installation.
|
||||
|
||||
Migrate IPA schema, configuration, and database to a local IPA server. This
|
||||
migration can be done online, where the tool will query the remote server. Or,
|
||||
@@ -19,7 +19,6 @@ and then use an exported LDIF file for the database migration portion (this
|
||||
might be more useful for very large databases as you don't need to worry about
|
||||
network interruptions)
|
||||
|
||||
-.SH POSITIONAL ARGUMENTS
|
||||
.TP
|
||||
\fBprod\-mode\fR
|
||||
In this mode everything will be migrated including the current user SIDs and
|
||||
@@ -28,13 +27,10 @@ DNA ranges
|
||||
\fBstage\-mode\fR
|
||||
In this mode, SIDs & DNA ranges are not migrated, and DNA attributes are reset
|
||||
|
||||
-.SH "COMMANDS"
|
||||
+.SH "OPTIONS"
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-verbose\fR
|
||||
-Use verbose output while running the migration tool.
|
||||
-.TP
|
||||
-\fB\-e\fR, \fB\-\-hostname=HOSTNAME\fR
|
||||
-The host name of the remote IPA server that is being migrated from.
|
||||
+Use verbose output while running the migration tool
|
||||
.TP
|
||||
\fB\-D\fR, \fB\-\-bind\-dn=BIND_DN\fR
|
||||
The Bind DN (Distinguished Name) or an LDAP entry to bind to the remote IPA server with.
|
||||
@@ -43,10 +39,10 @@ access to read the userPassword attribute. If ommitted the default is "cn=direc
|
||||
.TP
|
||||
\fB\-w\fR, \fB\-\-bind\-pw=PASSWORD\fR
|
||||
The password for the Bind DN that is authenticating against the remote IPA server. If
|
||||
-a password is not provided then the tool with prompt for the password if needed.
|
||||
+a password is not provided then the tool with prompt for the password if needed
|
||||
.TP
|
||||
-\fB\-Just\fR, \fB\-\-bind\-pw\-file=FILE_PATH\fR
|
||||
-Path to a file containing the password for the Bind DN.
|
||||
+\fB\-j\fR, \fB\-\-bind\-pw\-file=FILE_PATH\fR
|
||||
+Path to a file containing the password for the Bind DN
|
||||
.TP
|
||||
\fB\-Z\fR, \fB\-\-cacertfile=FILE_PATH\fR
|
||||
Path to a file containing a CA Certificate that the remote server trusts
|
||||
@@ -55,23 +51,23 @@ Path to a file containing a CA Certificate that the remote server trusts
|
||||
Path to a file containing the migration log. By default the tool will use \fI/var/log/ipa-migrate.log\fR
|
||||
.TP
|
||||
\fB\-x\fR, \fB\-\-dryrun\fR
|
||||
-Go through the migration process but do not write and data to the new IPA server.
|
||||
+Go through the migration process but do not write any data to the new IPA server
|
||||
.TP
|
||||
\fB\-o\fR, \fB\-\-dryrun\-record=FILE_PATH\fR
|
||||
Go through the migration process but do not write any data to the new IPA server. However, write the
|
||||
-migration operations to an LDIF file which can be applied later or reused for multiple migrations.
|
||||
+migration operations to an LDIF file which can be applied later or reused for multiple migrations
|
||||
.TP
|
||||
\fB\-r\fR, \fB\-\-reset\-range\fR
|
||||
Reset the ID range for migrated users/groups. In "stage-mode" this is done automatically
|
||||
.TP
|
||||
\fB\-F\fR, \fB\-\-force\fR
|
||||
-Ignore any errors and continue to proceed with migration effort.
|
||||
+Ignore any errors and continue to proceed with migration effort
|
||||
.TP
|
||||
\fB\-q\fR, \fB\-\-quiet\fR
|
||||
-Only log errors during the migration process.
|
||||
+Only log errors during the migration process
|
||||
.TP
|
||||
\fB\-B\fR, \fB\-\-migrate\-dns\fR
|
||||
-Migrate thr DNS records
|
||||
+Migrate the DNS records
|
||||
.TP
|
||||
\fB\-S\fR, \fB\-\-skip\-schema\fR
|
||||
Do not migrate the database schema
|
||||
@@ -80,21 +76,21 @@ Do not migrate the database schema
|
||||
Do not migrate the database configuration (dse.ldif/cn=config)
|
||||
.TP
|
||||
\fB\-O\fR, \fB\-\-schema\-overwrite\fR
|
||||
-Overwrite existing schema definitions. By default duplicate schema is skipped.
|
||||
+Overwrite existing schema definitions. By default duplicate schema is skipped
|
||||
.TP
|
||||
\fB\-s\fR, \fB\-\-subtree=DN\fR
|
||||
Specifies a custom database subtree that should be included in the migration.
|
||||
This is only needed if non-default subtrees/branches were added to the database
|
||||
-outside of IPA.
|
||||
+outside of IPA
|
||||
.TP
|
||||
\fB\-f\fR, \fB\-\-db\-ldif=FILE_PATH\fR
|
||||
-LDIF file containing the entire backend. If omitted the tool will query the remote IPA server.
|
||||
+LDIF file containing the entire backend. If omitted the tool will query the remote IPA server
|
||||
.TP
|
||||
\fB\-m\fR, \fB\-\-schema\-ldif=FILE_PATH\fR
|
||||
-LDIF file containing the schema. If omitted the tool will query the remote IPA server.
|
||||
+LDIF file containing the schema. If omitted the tool will query the remote IPA server
|
||||
.TP
|
||||
\fB\-g\fR, \fB\-\-config\-ldif=FILE_PATH\fR
|
||||
-LDIF file containing the entire "cn=config" DIT. If omitted the tool will query the remote IPA server.
|
||||
+LDIF file containing the entire "cn=config" DIT. If omitted the tool will query the remote IPA server
|
||||
.TP
|
||||
\fB\-n\fR, \fB\-\-no\-prompt\fR
|
||||
Do not prompt for confirmation before starting migration. Use at your own risk!
|
||||
--
|
||||
2.46.2
|
||||
|
@ -0,0 +1,61 @@
|
||||
From 7f4e7e1d6a2ae9d05a2dfcf620f4df07d09d9d2b Mon Sep 17 00:00:00 2001
|
||||
From: Sudhir Menon <sumenon@redhat.com>
|
||||
Date: Thu, 3 Oct 2024 18:45:31 +0530
|
||||
Subject: [PATCH] ipatests: Test for ipa hbac rule duplication
|
||||
|
||||
This test checks that ipa-migrate is not creating duplicate default hbac rules
|
||||
for allow_all and allow_systemd-user rules.
|
||||
|
||||
Related: https://pagure.io/freeipa/issue/9640
|
||||
|
||||
Signed-off-by: Sudhir Menon <sumenon@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
|
||||
---
|
||||
.../test_ipa_ipa_migration.py | 26 +++++++++++++++++++
|
||||
1 file changed, 26 insertions(+)
|
||||
|
||||
diff --git a/ipatests/test_integration/test_ipa_ipa_migration.py b/ipatests/test_integration/test_ipa_ipa_migration.py
|
||||
index 288165e8a83a96e6f6bd4e52866f98617f497c56..70c268951a0d7e40806742b16e62b764b2bae37b 100644
|
||||
--- a/ipatests/test_integration/test_ipa_ipa_migration.py
|
||||
+++ b/ipatests/test_integration/test_ipa_ipa_migration.py
|
||||
@@ -9,6 +9,7 @@ from __future__ import absolute_import
|
||||
from ipatests.test_integration.base import IntegrationTest
|
||||
from ipatests.pytest_ipa.integration import tasks
|
||||
from ipaplatform.paths import paths
|
||||
+from collections import Counter
|
||||
|
||||
import pytest
|
||||
import textwrap
|
||||
@@ -920,3 +921,28 @@ class TestIPAMigrateScenario1(IntegrationTest):
|
||||
)
|
||||
assert result.returncode == 1
|
||||
assert ERR_MSG in result.stderr_text
|
||||
+
|
||||
+ def test_ipa_hbac_rule_duplication(self):
|
||||
+ """
|
||||
+ This testcase checks that default hbac rules
|
||||
+ are not duplicated on the local server when
|
||||
+ ipa-migrate command is run.
|
||||
+ """
|
||||
+ run_migrate(
|
||||
+ self.replicas[0],
|
||||
+ "prod-mode",
|
||||
+ self.master.hostname,
|
||||
+ "cn=Directory Manager",
|
||||
+ self.master.config.admin_password,
|
||||
+ extra_args=['-n']
|
||||
+ )
|
||||
+ result = self.replicas[0].run_command(
|
||||
+ ['ipa', 'hbacrule-find']
|
||||
+ )
|
||||
+ lines = result.stdout_text.splitlines()
|
||||
+ line = []
|
||||
+ for i in lines:
|
||||
+ line.append(i.strip())
|
||||
+ count = Counter(line)
|
||||
+ assert count.get('Rule name: allow_all') < 2
|
||||
+ assert count.get('Rule name: allow_systemd-user') < 2
|
||||
--
|
||||
2.46.2
|
||||
|
@ -1,34 +0,0 @@
|
||||
From 44a762413c83f9637399afeb61b1e4b1ac111260 Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Feb 14 2024 12:24:48 +0000
|
||||
Subject: ipatests: fix tasks.wait_for_replication method
|
||||
|
||||
|
||||
With the fix for https://pagure.io/freeipa/issue/9171, the
|
||||
method entry.single_value['nsds5replicaupdateinprogress'] now
|
||||
returns a Boolean instead of a string "TRUE"/"FALSE".
|
||||
|
||||
The method tasks.wait_for_replication needs to be fixed so that
|
||||
it properly detects when replication is not done.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9530
|
||||
|
||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/ipatests/pytest_ipa/integration/tasks.py b/ipatests/pytest_ipa/integration/tasks.py
|
||||
index 9068ba6..952c9e6 100755
|
||||
--- a/ipatests/pytest_ipa/integration/tasks.py
|
||||
+++ b/ipatests/pytest_ipa/integration/tasks.py
|
||||
@@ -1510,7 +1510,7 @@ def wait_for_replication(ldap, timeout=30,
|
||||
statuses = [entry.single_value[status_attr] for entry in entries]
|
||||
wrong_statuses = [s for s in statuses
|
||||
if not re.match(target_status_re, s)]
|
||||
- if any(e.single_value[progress_attr] == 'TRUE' for e in entries):
|
||||
+ if any(e.single_value[progress_attr] for e in entries):
|
||||
msg = 'Replication not finished'
|
||||
logger.debug(msg)
|
||||
elif wrong_statuses:
|
||||
|
@ -1,127 +0,0 @@
|
||||
From 163f06cab678d517ab30ab6da59ae339f39ee7cf Mon Sep 17 00:00:00 2001
|
||||
From: Francisco Trivino <ftrivino@redhat.com>
|
||||
Date: Fri, 27 May 2022 17:31:40 +0200
|
||||
Subject: [PATCH] Vault: add support for RSA-OAEP wrapping algo
|
||||
|
||||
None of the FIPS certified modules in RHEL support PKCS#1 v1.5 as FIPS
|
||||
approved mechanism. This commit adds support for RSA-OAEP padding as a
|
||||
fallback.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9191
|
||||
|
||||
Signed-off-by: Francisco Trivino <ftrivino@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
(cherry picked from commit b1fb31fd20c900c9ff1d5d28dfe136439f6bf605)
|
||||
---
|
||||
ipaclient/plugins/vault.py | 57 ++++++++++++++++++++++++++++++--------
|
||||
1 file changed, 45 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py
|
||||
index d4c84eb6b..ed16c73ae 100644
|
||||
--- a/ipaclient/plugins/vault.py
|
||||
+++ b/ipaclient/plugins/vault.py
|
||||
@@ -119,8 +119,8 @@ def encrypt(data, symmetric_key=None, public_key=None):
|
||||
return public_key_obj.encrypt(
|
||||
data,
|
||||
padding.OAEP(
|
||||
- mgf=padding.MGF1(algorithm=hashes.SHA1()),
|
||||
- algorithm=hashes.SHA1(),
|
||||
+ mgf=padding.MGF1(algorithm=hashes.SHA256()),
|
||||
+ algorithm=hashes.SHA256(),
|
||||
label=None
|
||||
)
|
||||
)
|
||||
@@ -154,8 +154,8 @@ def decrypt(data, symmetric_key=None, private_key=None):
|
||||
return private_key_obj.decrypt(
|
||||
data,
|
||||
padding.OAEP(
|
||||
- mgf=padding.MGF1(algorithm=hashes.SHA1()),
|
||||
- algorithm=hashes.SHA1(),
|
||||
+ mgf=padding.MGF1(algorithm=hashes.SHA256()),
|
||||
+ algorithm=hashes.SHA256(),
|
||||
label=None
|
||||
)
|
||||
)
|
||||
@@ -705,14 +705,39 @@ class ModVaultData(Local):
|
||||
return transport_cert, wrapping_algo
|
||||
|
||||
def _do_internal(self, algo, transport_cert, raise_unexpected,
|
||||
- *args, **options):
|
||||
+ use_oaep=False, *args, **options):
|
||||
public_key = transport_cert.public_key()
|
||||
|
||||
# wrap session key with transport certificate
|
||||
- wrapped_session_key = public_key.encrypt(
|
||||
- algo.key,
|
||||
- padding.PKCS1v15()
|
||||
- )
|
||||
+ # KRA may be configured using either the default PKCS1v15 or RSA-OAEP.
|
||||
+ # there is no way to query this info using the REST interface.
|
||||
+ if not use_oaep:
|
||||
+ # PKCS1v15() causes an OpenSSL exception when FIPS is enabled
|
||||
+ # if so, we fallback to RSA-OAEP
|
||||
+ try:
|
||||
+ wrapped_session_key = public_key.encrypt(
|
||||
+ algo.key,
|
||||
+ padding.PKCS1v15()
|
||||
+ )
|
||||
+ except ValueError:
|
||||
+ wrapped_session_key = public_key.encrypt(
|
||||
+ algo.key,
|
||||
+ padding.OAEP(
|
||||
+ mgf=padding.MGF1(algorithm=hashes.SHA256()),
|
||||
+ algorithm=hashes.SHA256(),
|
||||
+ label=None
|
||||
+ )
|
||||
+ )
|
||||
+ else:
|
||||
+ wrapped_session_key = public_key.encrypt(
|
||||
+ algo.key,
|
||||
+ padding.OAEP(
|
||||
+ mgf=padding.MGF1(algorithm=hashes.SHA256()),
|
||||
+ algorithm=hashes.SHA256(),
|
||||
+ label=None
|
||||
+ )
|
||||
+ )
|
||||
+
|
||||
options['session_key'] = wrapped_session_key
|
||||
|
||||
name = self.name + '_internal'
|
||||
@@ -723,7 +748,7 @@ class ModVaultData(Local):
|
||||
errors.ExecutionError,
|
||||
errors.GenericError):
|
||||
_kra_config_cache.remove(self.api.env.domain)
|
||||
- if raise_unexpected:
|
||||
+ if raise_unexpected and use_oaep:
|
||||
raise
|
||||
return None
|
||||
|
||||
@@ -733,15 +758,23 @@ class ModVaultData(Local):
|
||||
"""
|
||||
# try call with cached transport certificate
|
||||
result = self._do_internal(algo, transport_cert, False,
|
||||
- *args, **options)
|
||||
+ False, *args, **options)
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
# retrieve transport certificate (cached by vaultconfig_show)
|
||||
transport_cert = self._get_vaultconfig(force_refresh=True)[0]
|
||||
+
|
||||
# call with the retrieved transport certificate
|
||||
+ result = self._do_internal(algo, transport_cert, True,
|
||||
+ False, *args, **options)
|
||||
+
|
||||
+ if result is not None:
|
||||
+ return result
|
||||
+
|
||||
+ # call and use_oaep this time, last attempt
|
||||
return self._do_internal(algo, transport_cert, True,
|
||||
- *args, **options)
|
||||
+ True, *args, **options)
|
||||
|
||||
|
||||
@register(no_fail=True)
|
||||
--
|
||||
2.43.0
|
||||
|
@ -0,0 +1,116 @@
|
||||
From 142f52fc981fe9f1d693b79a7b49506af2e98829 Mon Sep 17 00:00:00 2001
|
||||
From: Mohammad Rizwan <myusuf@redhat.com>
|
||||
Date: Mon, 19 Aug 2024 16:08:53 +0530
|
||||
Subject: [PATCH] ipatests: refactor password file handling in TestHSMInstall
|
||||
|
||||
When token and associated certs are not being cleaned
|
||||
up properly, the subsequent installation fails. Hence
|
||||
Password file related scenarios moved out to new test class
|
||||
so that it have fresh installation.
|
||||
|
||||
Signed-off-by: Mohammad Rizwan <myusuf@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
|
||||
---
|
||||
.../nightly_ipa-4-12_latest.yaml | 12 ++++++++
|
||||
.../nightly_ipa-4-12_latest_selinux.yaml | 13 ++++++++
|
||||
ipatests/test_integration/test_hsm.py | 30 ++++++++++---------
|
||||
3 files changed, 41 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/ipatests/prci_definitions/nightly_ipa-4-12_latest.yaml b/ipatests/prci_definitions/nightly_ipa-4-12_latest.yaml
|
||||
index 6d18e708fb0512ce21d8db68d4f1ab26849f40b7..07e2a8399ae4cc953adb415b975101ed20c67fd2 100644
|
||||
--- a/ipatests/prci_definitions/nightly_ipa-4-12_latest.yaml
|
||||
+++ b/ipatests/prci_definitions/nightly_ipa-4-12_latest.yaml
|
||||
@@ -1950,6 +1950,18 @@ jobs:
|
||||
timeout: 6300
|
||||
topology: *master_3repl_1client
|
||||
|
||||
+ fedora-latest-ipa-4-12/test_hsm_TestHSMInstallPasswordFile:
|
||||
+ requires: [fedora-latest-ipa-4-12/build]
|
||||
+ priority: 50
|
||||
+ job:
|
||||
+ class: RunPytest
|
||||
+ args:
|
||||
+ build_url: '{fedora-latest-ipa-4-12/build_url}'
|
||||
+ test_suite: test_integration/test_hsm.py::TestHSMInstallPasswordFile
|
||||
+ template: *ci-ipa-4-12-latest
|
||||
+ timeout: 6300
|
||||
+ topology: *master_1repl
|
||||
+
|
||||
fedora-latest-ipa-4-12/test_hsm_TestHSMInstallADTrustBase:
|
||||
requires: [fedora-latest-ipa-4-12/build]
|
||||
priority: 50
|
||||
diff --git a/ipatests/prci_definitions/nightly_ipa-4-12_latest_selinux.yaml b/ipatests/prci_definitions/nightly_ipa-4-12_latest_selinux.yaml
|
||||
index 52686df9713975c9590b8a99edb7c3442531fecc..11046be13fca1e7403d0fd74329a66ded3927a6c 100644
|
||||
--- a/ipatests/prci_definitions/nightly_ipa-4-12_latest_selinux.yaml
|
||||
+++ b/ipatests/prci_definitions/nightly_ipa-4-12_latest_selinux.yaml
|
||||
@@ -2105,6 +2105,19 @@ jobs:
|
||||
timeout: 6300
|
||||
topology: *master_3repl_1client
|
||||
|
||||
+ fedora-latest-ipa-4-12/test_hsm_TestHSMInstallPasswordFile:
|
||||
+ requires: [fedora-latest-ipa-4-12/build]
|
||||
+ priority: 50
|
||||
+ job:
|
||||
+ class: RunPytest
|
||||
+ args:
|
||||
+ build_url: '{fedora-latest-ipa-4-12/build_url}'
|
||||
+ selinux_enforcing: True
|
||||
+ test_suite: test_integration/test_hsm.py::TestHSMInstallPasswordFile
|
||||
+ template: *ci-ipa-4-12-latest
|
||||
+ timeout: 6300
|
||||
+ topology: *master_1repl
|
||||
+
|
||||
fedora-latest-ipa-4-12/test_hsm_TestHSMInstallADTrustBase:
|
||||
requires: [fedora-latest-ipa-4-12/build]
|
||||
priority: 50
|
||||
diff --git a/ipatests/test_integration/test_hsm.py b/ipatests/test_integration/test_hsm.py
|
||||
index 374f5c25fd3453cd45a15d2b0f20cee424282595..42895fcd60a7c02d3b6103c2f6751a367da30b2f 100644
|
||||
--- a/ipatests/test_integration/test_hsm.py
|
||||
+++ b/ipatests/test_integration/test_hsm.py
|
||||
@@ -312,24 +312,26 @@ class TestHSMInstall(BaseHSMTest):
|
||||
assert returncode == 0
|
||||
assert output == "No issues found."
|
||||
|
||||
- def test_hsm_install_server_password_file(self):
|
||||
- check_version(self.master)
|
||||
- # cleanup before fresh install with password file
|
||||
- for client in self.clients:
|
||||
- tasks.uninstall_client(client)
|
||||
|
||||
- for replica in self.replicas:
|
||||
- tasks.uninstall_master(replica)
|
||||
+class TestHSMInstallPasswordFile(BaseHSMTest):
|
||||
|
||||
- tasks.uninstall_master(self.master)
|
||||
+ num_replicas = 1
|
||||
|
||||
- delete_hsm_token([self.master] + self.replicas, self.token_name)
|
||||
- self.token_name, self.token_password = get_hsm_token(self.master)
|
||||
- self.master.put_file_contents(self.token_password_file,
|
||||
- self.token_password)
|
||||
- self.replicas[0].put_file_contents(self.token_password_file,
|
||||
- self.token_password)
|
||||
+ @classmethod
|
||||
+ def install(cls, mh):
|
||||
+ check_version(cls.master)
|
||||
+ # Enable pkiuser to read softhsm tokens
|
||||
+ cls.master.run_command(['usermod', 'pkiuser', '-a', '-G', 'ods'])
|
||||
+ cls.token_name, cls.token_password = get_hsm_token(cls.master)
|
||||
+ cls.master.put_file_contents(
|
||||
+ cls.token_password_file, cls.token_password
|
||||
+ )
|
||||
+ cls.replicas[0].put_file_contents(
|
||||
+ cls.token_password_file, cls.token_password
|
||||
+ )
|
||||
|
||||
+ def test_hsm_install_server_password_file(self):
|
||||
+ check_version(self.master)
|
||||
tasks.install_master(
|
||||
self.master, setup_dns=self.master_with_dns,
|
||||
setup_kra=self.master_with_kra,
|
||||
--
|
||||
2.46.2
|
||||
|
@ -1,88 +0,0 @@
|
||||
From 84798137fabf75fe79aebbd97e4b8418de8ab0f2 Mon Sep 17 00:00:00 2001
|
||||
From: Francisco Trivino <ftrivino@redhat.com>
|
||||
Date: Fri, 19 Jan 2024 18:15:28 +0100
|
||||
Subject: [PATCH] Vault: improve vault server archival/retrieval calls
|
||||
error handling
|
||||
|
||||
If a vault operation fails, the error message just says "InternalError". This commit
|
||||
improves error handling of key archival and retrieval calls by catching the PKIException
|
||||
error and raising it as an IPA error.
|
||||
|
||||
Related: https://pagure.io/freeipa/issue/9191
|
||||
|
||||
Signed-off-by: Francisco Trivino <ftrivino@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
(cherry picked from commit dc1ab53f0aa0398d493f7440b5ec4d70d9c7d663)
|
||||
---
|
||||
ipaserver/plugins/vault.py | 40 +++++++++++++++++++++++++-------------
|
||||
1 file changed, 26 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/ipaserver/plugins/vault.py b/ipaserver/plugins/vault.py
|
||||
index 574c83a9a..13c4fac9a 100644
|
||||
--- a/ipaserver/plugins/vault.py
|
||||
+++ b/ipaserver/plugins/vault.py
|
||||
@@ -45,6 +45,7 @@ if api.env.in_server:
|
||||
import pki.key
|
||||
from pki.crypto import DES_EDE3_CBC_OID
|
||||
from pki.crypto import AES_128_CBC_OID
|
||||
+ from pki import PKIException
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
@@ -1094,16 +1095,21 @@ class vault_archive_internal(PKQuery):
|
||||
pki.key.KeyClient.KEY_STATUS_INACTIVE)
|
||||
|
||||
# forward wrapped data to KRA
|
||||
- kra_client.keys.archive_encrypted_data(
|
||||
- client_key_id,
|
||||
- pki.key.KeyClient.PASS_PHRASE_TYPE,
|
||||
- wrapped_vault_data,
|
||||
- wrapped_session_key,
|
||||
- algorithm_oid=algorithm_oid,
|
||||
- nonce_iv=nonce,
|
||||
- )
|
||||
-
|
||||
- kra_account.logout()
|
||||
+ try:
|
||||
+ kra_client.keys.archive_encrypted_data(
|
||||
+ client_key_id,
|
||||
+ pki.key.KeyClient.PASS_PHRASE_TYPE,
|
||||
+ wrapped_vault_data,
|
||||
+ wrapped_session_key,
|
||||
+ algorithm_oid=algorithm_oid,
|
||||
+ nonce_iv=nonce,
|
||||
+ )
|
||||
+ except PKIException as e:
|
||||
+ kra_account.logout()
|
||||
+ raise errors.EncodingError(
|
||||
+ message=_("Unable to archive key: %s") % e)
|
||||
+ finally:
|
||||
+ kra_account.logout()
|
||||
|
||||
response = {
|
||||
'value': args[-1],
|
||||
@@ -1174,11 +1180,17 @@ class vault_retrieve_internal(PKQuery):
|
||||
kra_client.keys.encrypt_alg_oid = algorithm_oid
|
||||
|
||||
# retrieve encrypted data from KRA
|
||||
- key = kra_client.keys.retrieve_key(
|
||||
- key_info.get_key_id(),
|
||||
- wrapped_session_key)
|
||||
+ try:
|
||||
|
||||
- kra_account.logout()
|
||||
+ key = kra_client.keys.retrieve_key(
|
||||
+ key_info.get_key_id(),
|
||||
+ wrapped_session_key)
|
||||
+ except PKIException as e:
|
||||
+ kra_account.logout()
|
||||
+ raise errors.EncodingError(
|
||||
+ message=_("Unable to retrieve key: %s") % e)
|
||||
+ finally:
|
||||
+ kra_account.logout()
|
||||
|
||||
response = {
|
||||
'value': args[-1],
|
||||
--
|
||||
2.43.0
|
||||
|
276
SOURCES/0020-ipatests-2FA-test-cases.patch
Normal file
276
SOURCES/0020-ipatests-2FA-test-cases.patch
Normal file
@ -0,0 +1,276 @@
|
||||
From 6ac11ae003740faf19f3c75bf542ec44f717114f Mon Sep 17 00:00:00 2001
|
||||
From: Madhuri Upadhye <mupadhye@redhat.com>
|
||||
Date: Tue, 23 Jul 2024 18:14:36 +0530
|
||||
Subject: [PATCH] ipatests: 2FA test cases
|
||||
|
||||
Added following:
|
||||
|
||||
Added 'ssh_2fa_with_cmd' method for authentication,
|
||||
as for '\n' with paramiko did not work. In a test case
|
||||
need to just press `Enter` for `second factor`.
|
||||
Advantage of above function is no having paramiko
|
||||
dependancy.
|
||||
We can run the any command in same session after
|
||||
authentication of user.
|
||||
|
||||
Test cases:
|
||||
1. Authenticate the user only with password,
|
||||
just press enter at `Second factor` and check tgt after auth.
|
||||
when User authentication types: otp, password
|
||||
2. Authenticate the user with password and otpvalues and
|
||||
check tgt of user after auth when
|
||||
User authentication types: otp, password
|
||||
|
||||
related: https://github.com/SSSD/sssd/pull/7500
|
||||
|
||||
Signed-off-by: Madhuri Upadhye <mupadhye@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
---
|
||||
ipatests/test_integration/test_otp.py | 192 ++++++++++++++++++++++++--
|
||||
1 file changed, 181 insertions(+), 11 deletions(-)
|
||||
|
||||
diff --git a/ipatests/test_integration/test_otp.py b/ipatests/test_integration/test_otp.py
|
||||
index 878b4fb560ba8d7768ead54b065656462545babd..0babb45897c6107bf354477dbb0d3a805a3116f5 100644
|
||||
--- a/ipatests/test_integration/test_otp.py
|
||||
+++ b/ipatests/test_integration/test_otp.py
|
||||
@@ -5,26 +5,27 @@
|
||||
"""
|
||||
import base64
|
||||
import logging
|
||||
-import pytest
|
||||
import re
|
||||
-import time
|
||||
+import tempfile
|
||||
import textwrap
|
||||
-from urllib.parse import urlparse, parse_qs
|
||||
-from paramiko import AuthenticationException
|
||||
+import time
|
||||
+from urllib.parse import parse_qs, urlparse
|
||||
|
||||
+import pytest
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives.twofactor.hotp import HOTP
|
||||
from cryptography.hazmat.primitives.twofactor.totp import TOTP
|
||||
-
|
||||
-from ipatests.test_integration.base import IntegrationTest
|
||||
-from ipaplatform.paths import paths
|
||||
-from ipatests.pytest_ipa.integration import tasks
|
||||
-from ipapython.dn import DN
|
||||
-
|
||||
from ldap.controls.simple import BooleanControl
|
||||
+from paramiko import AuthenticationException
|
||||
|
||||
from ipalib import errors
|
||||
+from ipaplatform.osinfo import osinfo
|
||||
+from ipaplatform.paths import paths
|
||||
+from ipapython.dn import DN
|
||||
+from ipatests.pytest_ipa.integration import tasks
|
||||
+from ipatests.test_integration.base import IntegrationTest
|
||||
+from ipatests.util import xfail_context
|
||||
|
||||
PASSWORD = "DummyPassword123"
|
||||
USER = "opttestuser"
|
||||
@@ -84,6 +85,65 @@ def kinit_otp(host, user, *, password, otp, success=True):
|
||||
)
|
||||
|
||||
|
||||
+def ssh_2fa_with_cmd(host, hostname, username, password, otpvalue,
|
||||
+ command="exit 0"):
|
||||
+ """ ssh to user and in same session pass the command to check tgt of user
|
||||
+ :param host: host to ssh
|
||||
+ :param hostname: hostname to ssh
|
||||
+ :param str username: The name of user
|
||||
+ :param str password: password, usually the first factor
|
||||
+ :param str otpvalue: generated pin of user
|
||||
+ :param str command: command to execute in same session,
|
||||
+ by deafult set to "exit 0"
|
||||
+ :return: object class of expect command run
|
||||
+ """
|
||||
+ temp_conf = tempfile.NamedTemporaryFile(suffix='.exp', delete=False)
|
||||
+ with open(temp_conf.name, 'w') as tfile:
|
||||
+ tfile.write('proc exitmsg { msg code } {\n')
|
||||
+ tfile.write('\t# Close spawned program, if we are in the prompt\n')
|
||||
+ tfile.write('\tcatch close\n\n')
|
||||
+ tfile.write('\t# Wait for the exit code\n')
|
||||
+ tfile.write('\tlassign [wait] pid spawnid os_error_flag rc\n\n')
|
||||
+ tfile.write('\tputs ""\n')
|
||||
+ tfile.write('\tputs "expect result: $msg"\n')
|
||||
+ tfile.write('\tputs "expect exit code: $code"\n')
|
||||
+ tfile.write('\tputs "expect spawn exit code: $rc"\n')
|
||||
+ tfile.write('\texit $code\n')
|
||||
+ tfile.write('}\n')
|
||||
+ tfile.write('set timeout 60\n')
|
||||
+ tfile.write('set prompt ".*\\[#\\$>\\] $"\n')
|
||||
+ tfile.write(f'set password "{password}"\n')
|
||||
+ tfile.write(f'set otpvalue "{otpvalue}"\n')
|
||||
+ tfile.write(f'spawn ssh -o NumberOfPasswordPrompts=1 -o '
|
||||
+ f'StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'
|
||||
+ f' -l {username} {hostname} {command}\n')
|
||||
+ tfile.write('expect {\n')
|
||||
+ tfile.write('"Enter first factor:*" {send -- "$password\r"}\n')
|
||||
+ tfile.write('timeout {exitmsg "Unexpected output" 201}\n')
|
||||
+ tfile.write('eof {exitmsg "Unexpected end of file" 202}\n')
|
||||
+ tfile.write('}\n')
|
||||
+ tfile.write('expect {\n')
|
||||
+ tfile.write('"Enter second factor:*" {send -- "$otpvalue\r"}\n')
|
||||
+ tfile.write('timeout {exitmsg "Unexpected output" 201}\n')
|
||||
+ tfile.write('eof {exitmsg "Unexpected end of file" 202}\n')
|
||||
+ tfile.write('}\n')
|
||||
+ tfile.write('expect {\n')
|
||||
+ tfile.write('"Authentication failure" '
|
||||
+ '{exitmsg "Authentication failure" 1}\n')
|
||||
+ tfile.write('eof {exitmsg "Authentication successful" 0}\n')
|
||||
+ tfile.write('timeout {exitmsg "Unexpected output" 201}\n')
|
||||
+ tfile.write('}\n')
|
||||
+ tfile.write('expect {\n')
|
||||
+ tfile.write('exitmsg "Unexpected code path" 203\n')
|
||||
+ tfile.write('EOF\n')
|
||||
+ tfile.write('}')
|
||||
+ host.transport.put_file(temp_conf.name, '/tmp/ssh.exp')
|
||||
+ tasks.clear_sssd_cache(host)
|
||||
+ expect_cmd = 'expect -f /tmp/ssh.exp'
|
||||
+ cmd = host.run_command(expect_cmd, raiseonerr=False)
|
||||
+ return cmd
|
||||
+
|
||||
+
|
||||
def ssh_2f(hostname, username, answers_dict, port=22, unwanted_prompt=""):
|
||||
"""
|
||||
:param hostname: hostname
|
||||
@@ -91,6 +151,7 @@ def ssh_2f(hostname, username, answers_dict, port=22, unwanted_prompt=""):
|
||||
:param answers_dict: dictionary of options with prompt_message and value.
|
||||
:param port: port for ssh
|
||||
"""
|
||||
+
|
||||
# Handler for server questions
|
||||
def answer_handler(title, instructions, prompt_list):
|
||||
resp = []
|
||||
@@ -131,8 +192,9 @@ class TestOTPToken(IntegrationTest):
|
||||
|
||||
@classmethod
|
||||
def install(cls, mh):
|
||||
- super(TestOTPToken, cls).install(mh)
|
||||
master = cls.master
|
||||
+ tasks.install_packages(master, ['expect'])
|
||||
+ super(TestOTPToken, cls).install(mh)
|
||||
|
||||
tasks.kinit_admin(master)
|
||||
# create service with OTP auth indicator
|
||||
@@ -398,6 +460,114 @@ class TestOTPToken(IntegrationTest):
|
||||
self.master.run_command(['semanage', 'login', '-D'])
|
||||
sssd_conf_backup.restore()
|
||||
|
||||
+ def test_2fa_only_with_password(self):
|
||||
+ """Test ssh with 2FA only with the password(first factor) when
|
||||
+ user-auth-type is opt and password.
|
||||
+
|
||||
+ Test for : https://github.com/SSSD/sssd/pull/7500
|
||||
+
|
||||
+ Add the IPA user and user-auth-type set to opt and password.
|
||||
+ Authenticate the user only with password, just press enter
|
||||
+ at `Second factor`
|
||||
+ """
|
||||
+ master = self.master
|
||||
+ USER3 = 'sshuser3'
|
||||
+ sssd_conf_backup = tasks.FileBackup(master, paths.SSSD_CONF)
|
||||
+ first_prompt = 'Enter first factor:'
|
||||
+ second_prompt = 'Enter second factor:'
|
||||
+ add_contents = textwrap.dedent('''
|
||||
+ [prompting/2fa/sshd]
|
||||
+ single_prompt = False
|
||||
+ first_prompt = {0}
|
||||
+ second_prompt = {1}
|
||||
+ ''').format(first_prompt, second_prompt)
|
||||
+ set_sssd_conf(master, add_contents)
|
||||
+ tasks.create_active_user(master, USER3, PASSWORD)
|
||||
+ tasks.kinit_admin(master)
|
||||
+ master.run_command(['ipa', 'user-mod', USER3, '--user-auth-type=otp',
|
||||
+ '--user-auth-type=password'])
|
||||
+ try:
|
||||
+ otpuid, totp = add_otptoken(master, USER3, otptype='totp')
|
||||
+ master.run_command(['ipa', 'otptoken-show', otpuid])
|
||||
+ totp.generate(int(time.time())).decode('ascii')
|
||||
+ otpvalue = "\n"
|
||||
+ tasks.clear_sssd_cache(self.master)
|
||||
+ github_ticket = "https://github.com/SSSD/sssd/pull/7500"
|
||||
+ sssd_version = tasks.get_sssd_version(master)
|
||||
+ rhel_fail = (
|
||||
+ osinfo.id == 'rhel'
|
||||
+ and sssd_version < tasks.parse_version("2.9.5")
|
||||
+ )
|
||||
+ fedora_fail = (
|
||||
+ osinfo.id == 'fedora'
|
||||
+ and sssd_version == tasks.parse_version("2.9.5")
|
||||
+ )
|
||||
+ with xfail_context(rhel_fail or fedora_fail, reason=github_ticket):
|
||||
+ result = ssh_2fa_with_cmd(master,
|
||||
+ self.master.external_hostname,
|
||||
+ USER3, PASSWORD, otpvalue=otpvalue,
|
||||
+ command="klist")
|
||||
+ print(result.stdout_text)
|
||||
+ assert ('Authentication successful') in result.stdout_text
|
||||
+ assert USER3 in result.stdout_text
|
||||
+ assert (f'Default principal: '
|
||||
+ f'{USER3}@{self.master.domain.realm}' in
|
||||
+ result.stdout_text)
|
||||
+ cmd = self.master.run_command(['semanage', 'login', '-l'])
|
||||
+ assert USER3 in cmd.stdout_text
|
||||
+ finally:
|
||||
+ master.run_command(['ipa', 'user-del', USER3])
|
||||
+ self.master.run_command(['semanage', 'login', '-D'])
|
||||
+ sssd_conf_backup.restore()
|
||||
+
|
||||
+ def test_2fa_with_otp_password(self):
|
||||
+ """Test ssh with 2FA only with password and otpvalue when
|
||||
+ user-auth-type is opt and password.
|
||||
+
|
||||
+ Test for : https://github.com/SSSD/sssd/pull/7500
|
||||
+
|
||||
+ Add the IPA user and user-auth-type set to opt and password.
|
||||
+ Authenticate the user only with password and otpvalue.
|
||||
+ """
|
||||
+ master = self.master
|
||||
+ USER4 = 'sshuser4'
|
||||
+ sssd_conf_backup = tasks.FileBackup(master, paths.SSSD_CONF)
|
||||
+ first_prompt = 'Enter first factor:'
|
||||
+ second_prompt = 'Enter second factor:'
|
||||
+ add_contents = textwrap.dedent('''
|
||||
+ [prompting/2fa/sshd]
|
||||
+ single_prompt = False
|
||||
+ first_prompt = {0}
|
||||
+ second_prompt = {1}
|
||||
+ ''').format(first_prompt, second_prompt)
|
||||
+ set_sssd_conf(master, add_contents)
|
||||
+ tasks.create_active_user(master, USER4, PASSWORD)
|
||||
+ tasks.kinit_admin(master)
|
||||
+
|
||||
+ master.run_command(['ipa', 'user-mod', USER4, '--user-auth-type=otp',
|
||||
+ '--user-auth-type=password'])
|
||||
+ try:
|
||||
+ otpuid, totp = add_otptoken(master, USER4, otptype='totp')
|
||||
+ master.run_command(['ipa', 'otptoken-show', otpuid])
|
||||
+ otpvalue = totp.generate(int(time.time())).decode('ascii')
|
||||
+ tasks.clear_sssd_cache(self.master)
|
||||
+ result = ssh_2fa_with_cmd(master,
|
||||
+ self.master.external_hostname,
|
||||
+ USER4, PASSWORD, otpvalue=otpvalue,
|
||||
+ command="klist")
|
||||
+ print(result.stdout_text)
|
||||
+ cmd = self.master.run_command(['semanage', 'login', '-l'])
|
||||
+ # check the output
|
||||
+ assert ('Authentication successful') in result.stdout_text
|
||||
+ assert USER4 in result.stdout_text
|
||||
+ assert (f'Default principal: {USER4}@'
|
||||
+ f'{self.master.domain.realm}' in result.stdout_text)
|
||||
+ assert USER4 in cmd.stdout_text
|
||||
+ finally:
|
||||
+ master.run_command(['ipa', 'user-del', USER4])
|
||||
+ self.master.run_command(['semanage', 'login', '-D'])
|
||||
+ sssd_conf_backup.restore()
|
||||
+
|
||||
@pytest.fixture
|
||||
def setup_otp_nsslapd(self):
|
||||
check_services = self.master.run_command(
|
||||
--
|
||||
2.46.2
|
||||
|
@ -0,0 +1,34 @@
|
||||
From 9a2de23eb5e00efa72189c4a86d9db1fab52c2ca Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Thu, 24 Oct 2024 11:49:17 -0400
|
||||
Subject: [PATCH] Small fixup to determine which ACME uninstaller to use
|
||||
|
||||
The conditional was <= 11.5.0 which it should have been
|
||||
< 11.6.0 to allow for small updates to the 11.5.0 branch.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9673
|
||||
Fixes: https://pagure.io/freeipa/issue/9674
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@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 4b0f4d274b0c33140ed6f939f1a3fd8b75930ff9..58421a1d8859e5dd1357e07fd605e84e49048951 100644
|
||||
--- a/ipaserver/install/dogtaginstance.py
|
||||
+++ b/ipaserver/install/dogtaginstance.py
|
||||
@@ -311,7 +311,7 @@ class DogtagInstance(service.Service):
|
||||
return
|
||||
elif (
|
||||
pki.util.Version("11.0.0") <= pki_version
|
||||
- <= pki.util.Version("11.5.0")
|
||||
+ < pki.util.Version("11.6.0")
|
||||
):
|
||||
args = ['pki-server', 'acme-remove']
|
||||
else:
|
||||
--
|
||||
2.47.0
|
||||
|
@ -1,98 +0,0 @@
|
||||
From a406fd9aec7d053c044e73f16b05489bebd84bc8 Mon Sep 17 00:00:00 2001
|
||||
From: Francisco Trivino <ftrivino@redhat.com>
|
||||
Date: Fri, 19 Jan 2024 17:12:07 +0100
|
||||
Subject: [PATCH] kra: set RSA-OAEP as default wrapping algo when FIPS is
|
||||
enabled
|
||||
|
||||
Vault uses PKCS1v15 as default padding wrapping algo, which is not an approved
|
||||
FIPS algorithm. This commit ensures that KRA is installed with RSA-OAEP if FIPS
|
||||
is enabled. It also handles upgrade path.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9191
|
||||
|
||||
Signed-off-by: Francisco Trivino <ftrivino@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
(cherry picked from commit f2eec9eb208e62f923375b9eaf34fcc491046a0d)
|
||||
---
|
||||
install/share/ipaca_default.ini | 3 +++
|
||||
ipaserver/install/dogtaginstance.py | 4 +++-
|
||||
ipaserver/install/krainstance.py | 12 ++++++++++++
|
||||
ipaserver/install/server/upgrade.py | 12 ++++++++++++
|
||||
4 files changed, 30 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/install/share/ipaca_default.ini b/install/share/ipaca_default.ini
|
||||
index 082f507b2..691f1e1b7 100644
|
||||
--- a/install/share/ipaca_default.ini
|
||||
+++ b/install/share/ipaca_default.ini
|
||||
@@ -166,3 +166,6 @@ pki_audit_signing_subject_dn=cn=KRA Audit,%(ipa_subject_base)s
|
||||
# We will use the dbuser created for the CA.
|
||||
pki_share_db=True
|
||||
pki_share_dbuser_dn=uid=pkidbuser,ou=people,o=ipaca
|
||||
+
|
||||
+# KRA padding, set RSA-OAEP in FIPS mode
|
||||
+pki_use_oaep_rsa_keywrap=%(fips_use_oaep_rsa_keywrap)s
|
||||
\ No newline at end of file
|
||||
diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py
|
||||
index c2c6b3f49..c3c726f68 100644
|
||||
--- a/ipaserver/install/dogtaginstance.py
|
||||
+++ b/ipaserver/install/dogtaginstance.py
|
||||
@@ -1020,7 +1020,9 @@ class PKIIniLoader:
|
||||
# for softhsm2 testing
|
||||
softhsm2_so=paths.LIBSOFTHSM2_SO,
|
||||
# Configure a more secure AJP password by default
|
||||
- ipa_ajp_secret=ipautil.ipa_generate_password(special=None)
|
||||
+ ipa_ajp_secret=ipautil.ipa_generate_password(special=None),
|
||||
+ # in FIPS mode use RSA-OAEP wrapping padding algo as default
|
||||
+ fips_use_oaep_rsa_keywrap=tasks.is_fips_enabled()
|
||||
)
|
||||
|
||||
@classmethod
|
||||
diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py
|
||||
index 13cb2dcaa..0e04840a1 100644
|
||||
--- a/ipaserver/install/krainstance.py
|
||||
+++ b/ipaserver/install/krainstance.py
|
||||
@@ -277,6 +277,18 @@ class KRAInstance(DogtagInstance):
|
||||
|
||||
# A restart is required
|
||||
|
||||
+ def enable_oaep_wrap_algo(self):
|
||||
+ """
|
||||
+ Enable KRA OAEP key wrap algorithm
|
||||
+ """
|
||||
+ with installutils.stopped_service('pki-tomcatd', 'pki-tomcat'):
|
||||
+ directivesetter.set_directive(
|
||||
+ self.config,
|
||||
+ 'keyWrap.useOAEP',
|
||||
+ 'true', quotes=False, separator='=')
|
||||
+
|
||||
+ # A restart is required
|
||||
+
|
||||
def update_cert_config(self, nickname, cert):
|
||||
"""
|
||||
When renewing a KRA subsystem certificate the configuration file
|
||||
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
|
||||
index e4dc7ae73..c84516b56 100644
|
||||
--- a/ipaserver/install/server/upgrade.py
|
||||
+++ b/ipaserver/install/server/upgrade.py
|
||||
@@ -1780,6 +1780,18 @@ def upgrade_configuration():
|
||||
else:
|
||||
logger.info('ephemeralRequest is already enabled')
|
||||
|
||||
+ if tasks.is_fips_enabled():
|
||||
+ logger.info('[Ensuring KRA OAEP wrap algo is enabled in FIPS]')
|
||||
+ value = directivesetter.get_directive(
|
||||
+ paths.KRA_CS_CFG_PATH,
|
||||
+ 'keyWrap.useOAEP',
|
||||
+ separator='=')
|
||||
+ if value is None or value.lower() != 'true':
|
||||
+ logger.info('Use the OAEP key wrap algo')
|
||||
+ kra.enable_oaep_wrap_algo()
|
||||
+ else:
|
||||
+ logger.info('OAEP key wrap algo is already enabled')
|
||||
+
|
||||
# several upgrade steps require running CA. If CA is configured,
|
||||
# always run ca.start() because we need to wait until CA is really ready
|
||||
# by checking status using http
|
||||
--
|
||||
2.43.0
|
||||
|
34
SOURCES/0022-UnsafeIPAddress-pass-flag-0-to-IPNetwork.patch
Normal file
34
SOURCES/0022-UnsafeIPAddress-pass-flag-0-to-IPNetwork.patch
Normal file
@ -0,0 +1,34 @@
|
||||
From a9e653ca36a0829ae59cd204e7388d7a6c91e082 Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Fri, 13 Sep 2024 09:58:36 +0200
|
||||
Subject: [PATCH] UnsafeIPAddress: pass flag=0 to IPNetwork
|
||||
|
||||
When parsing a string, the constructor tries to parse the value
|
||||
as an IP Address first, or falls back to an IPNetwork with the
|
||||
flags INET_PTON.
|
||||
|
||||
Use the flag 0 instead for an IPNetwork.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9645
|
||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
---
|
||||
ipapython/ipautil.py | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
|
||||
index 3e98bfd6a66f24933e7e4de8efb79f4f5bf8bd0e..c237d59fb4b8be4187fb0efb04b097ff4df6c182 100644
|
||||
--- a/ipapython/ipautil.py
|
||||
+++ b/ipapython/ipautil.py
|
||||
@@ -119,7 +119,7 @@ class UnsafeIPAddress(netaddr.IPAddress):
|
||||
if addr.version != 6:
|
||||
raise
|
||||
except ValueError:
|
||||
- self._net = netaddr.IPNetwork(addr, flags=self.netaddr_ip_flags)
|
||||
+ self._net = netaddr.IPNetwork(addr, flags=0)
|
||||
addr = self._net.ip
|
||||
super(UnsafeIPAddress, self).__init__(addr,
|
||||
flags=self.netaddr_ip_flags)
|
||||
--
|
||||
2.47.0
|
||||
|
@ -1,29 +0,0 @@
|
||||
From a8e433f7c8d844d9f337a34db09b0197f2dbc5af Mon Sep 17 00:00:00 2001
|
||||
From: Julien Rische <jrische@redhat.com>
|
||||
Date: Tue, 20 Feb 2024 15:14:24 +0100
|
||||
Subject: [PATCH] ipa-kdb: Fix double free in ipadb_reinit_mspac()
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9535
|
||||
|
||||
Signed-off-by: Julien Rische <jrische@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
(cherry picked from commit dd27d225524aa81c038a970961a4f878cf742e2a)
|
||||
---
|
||||
daemons/ipa-kdb/ipa_kdb_mspac.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_mspac.c b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
index deed513b9..0964d112a 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_mspac.c
|
||||
@@ -3084,6 +3084,7 @@ ipadb_reinit_mspac(struct ipadb_context *ipactx, bool force_reinit,
|
||||
}
|
||||
|
||||
free(resstr);
|
||||
+ resstr = NULL;
|
||||
|
||||
flat_server_name = get_server_netbios_name(ipactx);
|
||||
if (!flat_server_name) {
|
||||
--
|
||||
2.43.0
|
||||
|
@ -0,0 +1,35 @@
|
||||
From 3d0962014adda39b754c4274ccb5ca5d70963c33 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Mon, 21 Oct 2024 13:51:13 -0400
|
||||
Subject: [PATCH] ipa-migrate - dryrun write updates crashes when removing
|
||||
values
|
||||
|
||||
When removing values the mod value list is None and that leads to a
|
||||
crash when trying to iterate it. Instead check that the vals are not
|
||||
None before looping.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9682
|
||||
|
||||
Signed-off-by: MArk Reynolds <mreynolds@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipaserver/install/ipa_migrate.py | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ipaserver/install/ipa_migrate.py b/ipaserver/install/ipa_migrate.py
|
||||
index 38356aa23ea435e2a616f48356feaea7b50dd1e4..f35629378490d3d45ca97f2aa5b4390c67d660ed 100644
|
||||
--- a/ipaserver/install/ipa_migrate.py
|
||||
+++ b/ipaserver/install/ipa_migrate.py
|
||||
@@ -622,7 +622,7 @@ class IPAMigrate():
|
||||
else:
|
||||
action = "replace"
|
||||
ldif_entry += f"{action}: {attr}\n"
|
||||
- for val in vals:
|
||||
+ for val in list(vals or []):
|
||||
ldif_entry += get_ldif_attr_val(attr, val)
|
||||
ldif_entry += "-\n"
|
||||
ldif_entry += "\n"
|
||||
--
|
||||
2.47.0
|
||||
|
@ -1,392 +0,0 @@
|
||||
From b039f3087a13de3f34b230dbe29a7cfb1965700d Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Feb 23 2024 09:49:27 +0000
|
||||
Subject: rpcserver: validate Kerberos principal name before running kinit
|
||||
|
||||
|
||||
Do minimal validation of the Kerberos principal name when passing it to
|
||||
kinit command line tool. Also pass it as the final argument to prevent
|
||||
option injection.
|
||||
|
||||
Accepted Kerberos principals are:
|
||||
- user names, using the following regexp
|
||||
(username with optional @realm, no spaces or slashes in the name):
|
||||
"(?!^[0-9]+$)^[a-zA-Z0-9_.][a-zA-Z0-9_.-]*[a-zA-Z0-9_.$-]?@?[a-zA-Z0-9.-]*$"
|
||||
|
||||
- service names (with slash in the name but no spaces). Validation of
|
||||
the hostname is done. There is no validation of the service name.
|
||||
|
||||
The regular expression above also covers cases where a principal name
|
||||
starts with '-'. This prevents option injection as well.
|
||||
|
||||
This fixes CVE-2024-1481
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9541
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/ipalib/install/kinit.py b/ipalib/install/kinit.py
|
||||
index cc839ec..4ad4eaa 100644
|
||||
--- a/ipalib/install/kinit.py
|
||||
+++ b/ipalib/install/kinit.py
|
||||
@@ -6,12 +6,16 @@ from __future__ import absolute_import
|
||||
|
||||
import logging
|
||||
import os
|
||||
+import re
|
||||
import time
|
||||
|
||||
import gssapi
|
||||
|
||||
from ipaplatform.paths import paths
|
||||
from ipapython.ipautil import run
|
||||
+from ipalib.constants import PATTERN_GROUPUSER_NAME
|
||||
+from ipalib.util import validate_hostname
|
||||
+from ipalib import api
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -21,6 +25,40 @@ KRB5_KDC_UNREACH = 2529639068
|
||||
# A service is not available that s required to process the request
|
||||
KRB5KDC_ERR_SVC_UNAVAILABLE = 2529638941
|
||||
|
||||
+PATTERN_REALM = '@?([a-zA-Z0-9.-]*)$'
|
||||
+PATTERN_PRINCIPAL = '(' + PATTERN_GROUPUSER_NAME[:-1] + ')' + PATTERN_REALM
|
||||
+PATTERN_SERVICE = '([a-zA-Z0-9.-]+)/([a-zA-Z0-9.-]+)' + PATTERN_REALM
|
||||
+
|
||||
+user_pattern = re.compile(PATTERN_PRINCIPAL)
|
||||
+service_pattern = re.compile(PATTERN_SERVICE)
|
||||
+
|
||||
+
|
||||
+def validate_principal(principal):
|
||||
+ if not isinstance(principal, str):
|
||||
+ raise RuntimeError('Invalid principal: not a string')
|
||||
+ if ('/' in principal) and (' ' in principal):
|
||||
+ raise RuntimeError('Invalid principal: bad spacing')
|
||||
+ else:
|
||||
+ realm = None
|
||||
+ match = user_pattern.match(principal)
|
||||
+ if match is None:
|
||||
+ match = service_pattern.match(principal)
|
||||
+ if match is None:
|
||||
+ raise RuntimeError('Invalid principal: cannot parse')
|
||||
+ else:
|
||||
+ # service = match[1]
|
||||
+ hostname = match[2]
|
||||
+ realm = match[3]
|
||||
+ try:
|
||||
+ validate_hostname(hostname)
|
||||
+ except ValueError as e:
|
||||
+ raise RuntimeError(str(e))
|
||||
+ else: # user match, validate realm
|
||||
+ # username = match[1]
|
||||
+ realm = match[2]
|
||||
+ if realm and 'realm' in api.env and realm != api.env.realm:
|
||||
+ raise RuntimeError('Invalid principal: realm mismatch')
|
||||
+
|
||||
|
||||
def kinit_keytab(principal, keytab, ccache_name, config=None, attempts=1):
|
||||
"""
|
||||
@@ -29,6 +67,7 @@ def kinit_keytab(principal, keytab, ccache_name, config=None, attempts=1):
|
||||
The optional parameter 'attempts' specifies how many times the credential
|
||||
initialization should be attempted in case of non-responsive KDC.
|
||||
"""
|
||||
+ validate_principal(principal)
|
||||
errors_to_retry = {KRB5KDC_ERR_SVC_UNAVAILABLE,
|
||||
KRB5_KDC_UNREACH}
|
||||
logger.debug("Initializing principal %s using keytab %s",
|
||||
@@ -65,6 +104,7 @@ def kinit_keytab(principal, keytab, ccache_name, config=None, attempts=1):
|
||||
|
||||
return None
|
||||
|
||||
+
|
||||
def kinit_password(principal, password, ccache_name, config=None,
|
||||
armor_ccache_name=None, canonicalize=False,
|
||||
enterprise=False, lifetime=None):
|
||||
@@ -73,8 +113,9 @@ def kinit_password(principal, password, ccache_name, config=None,
|
||||
web-based authentication, use armor_ccache_path to specify http service
|
||||
ccache.
|
||||
"""
|
||||
+ validate_principal(principal)
|
||||
logger.debug("Initializing principal %s using password", principal)
|
||||
- args = [paths.KINIT, principal, '-c', ccache_name]
|
||||
+ args = [paths.KINIT, '-c', ccache_name]
|
||||
if armor_ccache_name is not None:
|
||||
logger.debug("Using armor ccache %s for FAST webauth",
|
||||
armor_ccache_name)
|
||||
@@ -91,6 +132,7 @@ def kinit_password(principal, password, ccache_name, config=None,
|
||||
logger.debug("Using enterprise principal")
|
||||
args.append('-E')
|
||||
|
||||
+ args.extend(['--', principal])
|
||||
env = {'LC_ALL': 'C'}
|
||||
if config is not None:
|
||||
env['KRB5_CONFIG'] = config
|
||||
@@ -154,6 +196,7 @@ def kinit_pkinit(
|
||||
|
||||
:raises: CalledProcessError if PKINIT fails
|
||||
"""
|
||||
+ validate_principal(principal)
|
||||
logger.debug(
|
||||
"Initializing principal %s using PKINIT %s", principal, user_identity
|
||||
)
|
||||
@@ -168,7 +211,7 @@ def kinit_pkinit(
|
||||
assert pkinit_anchor.startswith(("FILE:", "DIR:", "ENV:"))
|
||||
args.extend(["-X", f"X509_anchors={pkinit_anchor}"])
|
||||
args.extend(["-X", f"X509_user_identity={user_identity}"])
|
||||
- args.append(principal)
|
||||
+ args.extend(['--', principal])
|
||||
|
||||
# this workaround enables us to capture stderr and put it
|
||||
# into the raised exception in case of unsuccessful authentication
|
||||
diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py
|
||||
index 3555014..60bfa61 100644
|
||||
--- a/ipaserver/rpcserver.py
|
||||
+++ b/ipaserver/rpcserver.py
|
||||
@@ -1134,10 +1134,6 @@ class login_password(Backend, KerberosSession):
|
||||
canonicalize=True,
|
||||
lifetime=self.api.env.kinit_lifetime)
|
||||
|
||||
- if armor_path:
|
||||
- logger.debug('Cleanup the armor ccache')
|
||||
- ipautil.run([paths.KDESTROY, '-A', '-c', armor_path],
|
||||
- env={'KRB5CCNAME': armor_path}, raiseonerr=False)
|
||||
except RuntimeError as e:
|
||||
if ('kinit: Cannot read password while '
|
||||
'getting initial credentials') in str(e):
|
||||
@@ -1155,6 +1151,11 @@ class login_password(Backend, KerberosSession):
|
||||
raise KrbPrincipalWrongFAST(principal=principal)
|
||||
raise InvalidSessionPassword(principal=principal,
|
||||
message=unicode(e))
|
||||
+ finally:
|
||||
+ if armor_path:
|
||||
+ logger.debug('Cleanup the armor ccache')
|
||||
+ ipautil.run([paths.KDESTROY, '-A', '-c', armor_path],
|
||||
+ env={'KRB5CCNAME': armor_path}, raiseonerr=False)
|
||||
|
||||
|
||||
class change_password(Backend, HTTP_Status):
|
||||
diff --git a/ipatests/prci_definitions/gating.yaml b/ipatests/prci_definitions/gating.yaml
|
||||
index 91be057..400a248 100644
|
||||
--- a/ipatests/prci_definitions/gating.yaml
|
||||
+++ b/ipatests/prci_definitions/gating.yaml
|
||||
@@ -310,3 +310,15 @@ jobs:
|
||||
template: *ci-ipa-4-9-latest
|
||||
timeout: 3600
|
||||
topology: *master_1repl_1client
|
||||
+
|
||||
+ fedora-latest-ipa-4-9/test_ipalib_install:
|
||||
+ requires: [fedora-latest-ipa-4-9/build]
|
||||
+ priority: 100
|
||||
+ job:
|
||||
+ class: RunPytest
|
||||
+ args:
|
||||
+ build_url: '{fedora-latest-ipa-4-9/build_url}'
|
||||
+ test_suite: test_ipalib_install/test_kinit.py
|
||||
+ template: *ci-ipa-4-9-latest
|
||||
+ timeout: 600
|
||||
+ topology: *master_1repl
|
||||
diff --git a/ipatests/prci_definitions/nightly_ipa-4-9_latest.yaml b/ipatests/prci_definitions/nightly_ipa-4-9_latest.yaml
|
||||
index b2ab765..7c03a48 100644
|
||||
--- a/ipatests/prci_definitions/nightly_ipa-4-9_latest.yaml
|
||||
+++ b/ipatests/prci_definitions/nightly_ipa-4-9_latest.yaml
|
||||
@@ -1801,3 +1801,15 @@ jobs:
|
||||
template: *ci-ipa-4-9-latest
|
||||
timeout: 5000
|
||||
topology: *master_2repl_1client
|
||||
+
|
||||
+ fedora-latest-ipa-4-9/test_ipalib_install:
|
||||
+ requires: [fedora-latest-ipa-4-9/build]
|
||||
+ priority: 50
|
||||
+ job:
|
||||
+ class: RunPytest
|
||||
+ args:
|
||||
+ build_url: '{fedora-latest-ipa-4-9/build_url}'
|
||||
+ test_suite: test_ipalib_install/test_kinit.py
|
||||
+ template: *ci-ipa-4-9-latest
|
||||
+ timeout: 600
|
||||
+ topology: *master_1repl
|
||||
diff --git a/ipatests/prci_definitions/nightly_ipa-4-9_latest_selinux.yaml b/ipatests/prci_definitions/nightly_ipa-4-9_latest_selinux.yaml
|
||||
index b7b3d3b..802bd2a 100644
|
||||
--- a/ipatests/prci_definitions/nightly_ipa-4-9_latest_selinux.yaml
|
||||
+++ b/ipatests/prci_definitions/nightly_ipa-4-9_latest_selinux.yaml
|
||||
@@ -1944,3 +1944,16 @@ jobs:
|
||||
template: *ci-ipa-4-9-latest
|
||||
timeout: 5000
|
||||
topology: *master_2repl_1client
|
||||
+
|
||||
+ fedora-latest-ipa-4-9/test_ipalib_install:
|
||||
+ requires: [fedora-latest-ipa-4-9/build]
|
||||
+ priority: 50
|
||||
+ job:
|
||||
+ class: RunPytest
|
||||
+ args:
|
||||
+ build_url: '{fedora-latest-ipa-4-9/build_url}'
|
||||
+ selinux_enforcing: True
|
||||
+ test_suite: test_ipalib_install/test_kinit.py
|
||||
+ template: *ci-ipa-4-9-latest
|
||||
+ timeout: 600
|
||||
+ topology: *master_1repl
|
||||
diff --git a/ipatests/prci_definitions/nightly_ipa-4-9_previous.yaml b/ipatests/prci_definitions/nightly_ipa-4-9_previous.yaml
|
||||
index eb3849e..1e1adb8 100644
|
||||
--- a/ipatests/prci_definitions/nightly_ipa-4-9_previous.yaml
|
||||
+++ b/ipatests/prci_definitions/nightly_ipa-4-9_previous.yaml
|
||||
@@ -1801,3 +1801,15 @@ jobs:
|
||||
template: *ci-ipa-4-9-previous
|
||||
timeout: 5000
|
||||
topology: *master_2repl_1client
|
||||
+
|
||||
+ fedora-previous-ipa-4-9/test_ipalib_install:
|
||||
+ requires: [fedora-previous-ipa-4-9/build]
|
||||
+ priority: 50
|
||||
+ job:
|
||||
+ class: RunPytest
|
||||
+ args:
|
||||
+ build_url: '{fedora-previous-ipa-4-9/build_url}'
|
||||
+ test_suite: test_ipalib_install/test_kinit.py
|
||||
+ template: *ci-ipa-4-9-previous
|
||||
+ timeout: 600
|
||||
+ topology: *master_1repl
|
||||
diff --git a/ipatests/setup.py b/ipatests/setup.py
|
||||
index 6217a1b..0aec4a7 100644
|
||||
--- a/ipatests/setup.py
|
||||
+++ b/ipatests/setup.py
|
||||
@@ -41,6 +41,7 @@ if __name__ == '__main__':
|
||||
"ipatests.test_integration",
|
||||
"ipatests.test_ipaclient",
|
||||
"ipatests.test_ipalib",
|
||||
+ "ipatests.test_ipalib_install",
|
||||
"ipatests.test_ipaplatform",
|
||||
"ipatests.test_ipapython",
|
||||
"ipatests.test_ipaserver",
|
||||
diff --git a/ipatests/test_ipalib_install/__init__.py b/ipatests/test_ipalib_install/__init__.py
|
||||
new file mode 100644
|
||||
index 0000000..e69de29
|
||||
--- /dev/null
|
||||
+++ b/ipatests/test_ipalib_install/__init__.py
|
||||
diff --git a/ipatests/test_ipalib_install/test_kinit.py b/ipatests/test_ipalib_install/test_kinit.py
|
||||
new file mode 100644
|
||||
index 0000000..f89ea17
|
||||
--- /dev/null
|
||||
+++ b/ipatests/test_ipalib_install/test_kinit.py
|
||||
@@ -0,0 +1,29 @@
|
||||
+#
|
||||
+# Copyright (C) 2024 FreeIPA Contributors see COPYING for license
|
||||
+#
|
||||
+"""Tests for ipalib.install.kinit module
|
||||
+"""
|
||||
+
|
||||
+import pytest
|
||||
+
|
||||
+from ipalib.install.kinit import validate_principal
|
||||
+
|
||||
+
|
||||
+# None means no exception is expected
|
||||
+@pytest.mark.parametrize('principal, exception', [
|
||||
+ ('testuser', None),
|
||||
+ ('testuser@EXAMPLE.TEST', None),
|
||||
+ ('test/ipa.example.test', None),
|
||||
+ ('test/ipa.example.test@EXAMPLE.TEST', None),
|
||||
+ ('test/ipa@EXAMPLE.TEST', RuntimeError),
|
||||
+ ('test/-ipa.example.test@EXAMPLE.TEST', RuntimeError),
|
||||
+ ('test/ipa.1example.test@EXAMPLE.TEST', RuntimeError),
|
||||
+ ('test /ipa.example,test', RuntimeError),
|
||||
+ ('testuser@OTHER.TEST', RuntimeError),
|
||||
+ ('test/ipa.example.test@OTHER.TEST', RuntimeError),
|
||||
+])
|
||||
+def test_validate_principal(principal, exception):
|
||||
+ try:
|
||||
+ validate_principal(principal)
|
||||
+ except Exception as e:
|
||||
+ assert e.__class__ == exception
|
||||
|
||||
From 96a478bbedd49c31e0f078f00f2d1cb55bb952fd Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Feb 23 2024 09:49:27 +0000
|
||||
Subject: validate_principal: Don't try to verify that the realm is known
|
||||
|
||||
|
||||
The actual value is less important than whether it matches the
|
||||
regular expression. A number of legal but difficult to know in
|
||||
context realms could be passed in here (trust for example).
|
||||
|
||||
This fixes CVE-2024-1481
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9541
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/ipalib/install/kinit.py b/ipalib/install/kinit.py
|
||||
index 4ad4eaa..d5fb56b 100644
|
||||
--- a/ipalib/install/kinit.py
|
||||
+++ b/ipalib/install/kinit.py
|
||||
@@ -15,7 +15,6 @@ from ipaplatform.paths import paths
|
||||
from ipapython.ipautil import run
|
||||
from ipalib.constants import PATTERN_GROUPUSER_NAME
|
||||
from ipalib.util import validate_hostname
|
||||
-from ipalib import api
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -39,7 +38,9 @@ def validate_principal(principal):
|
||||
if ('/' in principal) and (' ' in principal):
|
||||
raise RuntimeError('Invalid principal: bad spacing')
|
||||
else:
|
||||
- realm = None
|
||||
+ # For a user match in the regex
|
||||
+ # username = match[1]
|
||||
+ # realm = match[2]
|
||||
match = user_pattern.match(principal)
|
||||
if match is None:
|
||||
match = service_pattern.match(principal)
|
||||
@@ -48,16 +49,11 @@ def validate_principal(principal):
|
||||
else:
|
||||
# service = match[1]
|
||||
hostname = match[2]
|
||||
- realm = match[3]
|
||||
+ # realm = match[3]
|
||||
try:
|
||||
validate_hostname(hostname)
|
||||
except ValueError as e:
|
||||
raise RuntimeError(str(e))
|
||||
- else: # user match, validate realm
|
||||
- # username = match[1]
|
||||
- realm = match[2]
|
||||
- if realm and 'realm' in api.env and realm != api.env.realm:
|
||||
- raise RuntimeError('Invalid principal: realm mismatch')
|
||||
|
||||
|
||||
def kinit_keytab(principal, keytab, ccache_name, config=None, attempts=1):
|
||||
diff --git a/ipatests/test_ipalib_install/test_kinit.py b/ipatests/test_ipalib_install/test_kinit.py
|
||||
index f89ea17..8289c4b 100644
|
||||
--- a/ipatests/test_ipalib_install/test_kinit.py
|
||||
+++ b/ipatests/test_ipalib_install/test_kinit.py
|
||||
@@ -17,13 +17,16 @@ from ipalib.install.kinit import validate_principal
|
||||
('test/ipa.example.test@EXAMPLE.TEST', None),
|
||||
('test/ipa@EXAMPLE.TEST', RuntimeError),
|
||||
('test/-ipa.example.test@EXAMPLE.TEST', RuntimeError),
|
||||
- ('test/ipa.1example.test@EXAMPLE.TEST', RuntimeError),
|
||||
+ ('test/ipa.1example.test@EXAMPLE.TEST', None),
|
||||
('test /ipa.example,test', RuntimeError),
|
||||
- ('testuser@OTHER.TEST', RuntimeError),
|
||||
- ('test/ipa.example.test@OTHER.TEST', RuntimeError),
|
||||
+ ('testuser@OTHER.TEST', None),
|
||||
+ ('test/ipa.example.test@OTHER.TEST', None)
|
||||
])
|
||||
def test_validate_principal(principal, exception):
|
||||
try:
|
||||
validate_principal(principal)
|
||||
except Exception as e:
|
||||
assert e.__class__ == exception
|
||||
+ else:
|
||||
+ if exception is not None:
|
||||
+ raise RuntimeError('Test should have failed')
|
||||
|
@ -1,43 +0,0 @@
|
||||
From d7c1ba0672fc8964f7674a526f3019429a551372 Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Mar 06 2024 08:34:57 +0000
|
||||
Subject: Vault: add additional fallback to RSA-OAEP wrapping algo
|
||||
|
||||
|
||||
There is a fallback when creating the wrapping key but one was missing
|
||||
when trying to use the cached transport_cert.
|
||||
|
||||
This allows, along with forcing keyWrap.useOAEP=true, vault creation
|
||||
on an nCipher HSM.
|
||||
|
||||
This can be seen in HSMs where the device doesn't support the
|
||||
PKCS#1 v1.5 mechanism. It will error out with either "invalid
|
||||
algorithm" or CKR_FUNCTION_FAILED.
|
||||
|
||||
Related: https://pagure.io/freeipa/issue/9191
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py
|
||||
index ed16c73..1523187 100644
|
||||
--- a/ipaclient/plugins/vault.py
|
||||
+++ b/ipaclient/plugins/vault.py
|
||||
@@ -757,8 +757,12 @@ class ModVaultData(Local):
|
||||
Calls the internal counterpart of the command.
|
||||
"""
|
||||
# try call with cached transport certificate
|
||||
- result = self._do_internal(algo, transport_cert, False,
|
||||
- False, *args, **options)
|
||||
+ try:
|
||||
+ result = self._do_internal(algo, transport_cert, False,
|
||||
+ False, *args, **options)
|
||||
+ except errors.EncodingError:
|
||||
+ result = self._do_internal(algo, transport_cert, False,
|
||||
+ True, *args, **options)
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
|
@ -0,0 +1,30 @@
|
||||
From 6bdb8603054fc60e9479f6aaf8b6315dfe508891 Mon Sep 17 00:00:00 2001
|
||||
From: Mark Reynolds <mreynolds@redhat.com>
|
||||
Date: Tue, 22 Oct 2024 13:00:03 -0400
|
||||
Subject: [PATCH] ipa-migrate should migrate dns forward zones
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9686
|
||||
|
||||
Signed-off-by: Mark Reynolds <mreynolds@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipaserver/install/ipa_migrate_constants.py | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ipaserver/install/ipa_migrate_constants.py b/ipaserver/install/ipa_migrate_constants.py
|
||||
index 250f1b5b01bf066d316a98489ab6153b89615173..c140414ea6c607a93e35ef0705480d1002b7945e 100644
|
||||
--- a/ipaserver/install/ipa_migrate_constants.py
|
||||
+++ b/ipaserver/install/ipa_migrate_constants.py
|
||||
@@ -993,7 +993,7 @@ DB_OBJECTS = {
|
||||
'count': 0,
|
||||
},
|
||||
'dns_records': {
|
||||
- 'oc': ['idnsrecord', 'idnszone'],
|
||||
+ 'oc': ['idnsrecord', 'idnszone', 'idnsforwardzone'],
|
||||
'subtree': ',cn=dns,$SUFFIX',
|
||||
'label': 'DNS Records',
|
||||
'mode': 'all',
|
||||
--
|
||||
2.47.0
|
||||
|
@ -1,50 +0,0 @@
|
||||
From 656a11ae961f8d1afad54567cfe8ccb53e084a67 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Mar 20 2024 10:06:07 +0000
|
||||
Subject: dcerpc: invalidate forest trust info cache when filtering out realm domains
|
||||
|
||||
|
||||
When get_realmdomains() method is called, it will filter out subdomains
|
||||
of the IPA primary domain. This is required because Active Directory
|
||||
domain controllers are assuming subdomains already covered by the main
|
||||
domain namespace.
|
||||
|
||||
[MS-LSAD] 3.1.4.7.16.1, 'Forest Trust Collision Generation' defines the
|
||||
method of validating the forest trust information. They are the same as
|
||||
rules in [MS-ADTS] section 6.1.6. Specifically,
|
||||
|
||||
- A top-level name must not be superior to an enabled top-level name
|
||||
for another trusted domain object, unless the current trusted domain
|
||||
object has a corresponding exclusion record.
|
||||
|
||||
In practice, we filtered those subdomains already but the code wasn't
|
||||
invalidating a previously retrieved forest trust information.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9551
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
|
||||
index b6139db..7ee553d 100644
|
||||
--- a/ipaserver/dcerpc.py
|
||||
+++ b/ipaserver/dcerpc.py
|
||||
@@ -1103,6 +1103,7 @@ class TrustDomainInstance:
|
||||
|
||||
info.count = len(ftinfo_records)
|
||||
info.entries = ftinfo_records
|
||||
+ another_domain.ftinfo_data = info
|
||||
return info
|
||||
|
||||
def clear_ftinfo_conflict(self, another_domain, cinfo):
|
||||
@@ -1778,6 +1779,7 @@ class TrustDomainJoins:
|
||||
return
|
||||
|
||||
self.local_domain.ftinfo_records = []
|
||||
+ self.local_domain.ftinfo_data = None
|
||||
|
||||
realm_domains = self.api.Command.realmdomains_show()['result']
|
||||
# Use realmdomains' modification timestamp
|
||||
|
784
SOURCES/0025-ipatests-Tests-for-ipa-migrate-tool.patch
Normal file
784
SOURCES/0025-ipatests-Tests-for-ipa-migrate-tool.patch
Normal file
@ -0,0 +1,784 @@
|
||||
From 9da927c8eec7db6d1c75c296eef45beb93797e58 Mon Sep 17 00:00:00 2001
|
||||
From: Sudhir Menon <sumenon@redhat.com>
|
||||
Date: Thu, 1 Aug 2024 16:30:16 +0530
|
||||
Subject: [PATCH] ipatests: Tests for ipa-migrate tool
|
||||
|
||||
This patch includes test to covers below scenarios
|
||||
|
||||
1. hbac and sudo rules are migrated to local server
|
||||
2. uid for user migrated varies in stage/prod mode.
|
||||
3. subids are migrated to local server
|
||||
4. idranges are migrated to local server
|
||||
5. vaults are not migrated to local server.
|
||||
6. Ensure trust related data is also migrated to local server
|
||||
7. Added paths.IPA_MIGRATE_LOG in ipatests/pytest_ipa/integration/__init__.py
|
||||
|
||||
Signed-off-by: Sudhir Menon <sumenon@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
---
|
||||
ipatests/pytest_ipa/integration/__init__.py | 2 +
|
||||
.../test_ipa_ipa_migration.py | 596 ++++++++++++++----
|
||||
2 files changed, 460 insertions(+), 138 deletions(-)
|
||||
|
||||
diff --git a/ipatests/pytest_ipa/integration/__init__.py b/ipatests/pytest_ipa/integration/__init__.py
|
||||
index 34b6ef0fb1e49fbb9c86e7496de50cf5cda5e91e..eb032cd72d2aa2a5ed4c476e3cb04dc77f607eaa 100644
|
||||
--- a/ipatests/pytest_ipa/integration/__init__.py
|
||||
+++ b/ipatests/pytest_ipa/integration/__init__.py
|
||||
@@ -88,6 +88,8 @@ CLASS_LOGFILES = [
|
||||
paths.VAR_LOG_AUDIT,
|
||||
# sssd
|
||||
paths.VAR_LOG_SSSD_DIR,
|
||||
+ # ipa-ipa-migration logs
|
||||
+ paths.IPA_MIGRATE_LOG,
|
||||
# system
|
||||
paths.RESOLV_CONF,
|
||||
paths.HOSTS,
|
||||
diff --git a/ipatests/test_integration/test_ipa_ipa_migration.py b/ipatests/test_integration/test_ipa_ipa_migration.py
|
||||
index 70c268951a0d7e40806742b16e62b764b2bae37b..d852ca63a6b3a7e7118d66ce1cd9bb98e56f1a73 100644
|
||||
--- a/ipatests/test_integration/test_ipa_ipa_migration.py
|
||||
+++ b/ipatests/test_integration/test_ipa_ipa_migration.py
|
||||
@@ -12,6 +12,7 @@ from ipaplatform.paths import paths
|
||||
from collections import Counter
|
||||
|
||||
import pytest
|
||||
+import re
|
||||
import textwrap
|
||||
|
||||
|
||||
@@ -65,29 +66,7 @@ def prepare_ipa_server(master):
|
||||
"--secondary-rid-base=400000",
|
||||
]
|
||||
)
|
||||
-
|
||||
- # Add Automount locations and maps
|
||||
- master.run_command(["ipa", "automountlocation-add", "baltimore"])
|
||||
- master.run_command(["ipa", "automountmap-add", "baltimore", "auto.share"])
|
||||
- master.run_command(
|
||||
- [
|
||||
- "ipa",
|
||||
- "automountmap-add-indirect",
|
||||
- "baltimore",
|
||||
- "--parentmap=auto.share",
|
||||
- "--mount=sub auto.man",
|
||||
- ]
|
||||
- )
|
||||
- master.run_command(
|
||||
- [
|
||||
- "ipa",
|
||||
- "automountkey-add",
|
||||
- "baltimore",
|
||||
- "auto.master",
|
||||
- "--key=/share",
|
||||
- "--info=auto.share",
|
||||
- ]
|
||||
- )
|
||||
+ master.run_command(["ipactl", "restart"])
|
||||
|
||||
# Run ipa-adtrust-install
|
||||
master.run_command(["dnf", "install", "-y", "ipa-server-trust-ad"])
|
||||
@@ -235,6 +214,17 @@ def prepare_ipa_server(master):
|
||||
["ipa", "hbacrule-add-service", "--hbacsvcs=sshd", "testuser_sshd"]
|
||||
)
|
||||
|
||||
+ # Add DNSForwardzone
|
||||
+ master.run_command(
|
||||
+ [
|
||||
+ "ipa",
|
||||
+ "dnsforwardzone-add",
|
||||
+ "forwardzone.test",
|
||||
+ "--forwarder",
|
||||
+ "10.11.12.13",
|
||||
+ ]
|
||||
+ )
|
||||
+
|
||||
# Vault addition
|
||||
master.run_command(
|
||||
[
|
||||
@@ -244,6 +234,7 @@ def prepare_ipa_server(master):
|
||||
"vault1234",
|
||||
"--type",
|
||||
"symmetric",
|
||||
+ "testvault",
|
||||
]
|
||||
)
|
||||
|
||||
@@ -260,7 +251,46 @@ def prepare_ipa_server(master):
|
||||
|
||||
# Modify passkeyconfig
|
||||
master.run_command(
|
||||
- ["ipa", "passkeyconfig-mod", "--require-user-verification=FALSE"]
|
||||
+ [
|
||||
+ "ipa", "passkeyconfig-mod",
|
||||
+ "--require-user-verification=FALSE"
|
||||
+ ]
|
||||
+ )
|
||||
+
|
||||
+ # Adding automountlocation, maps, keys
|
||||
+ master.run_command(
|
||||
+ [
|
||||
+ "ipa", "automountlocation-add",
|
||||
+ "baltimore"
|
||||
+ ]
|
||||
+ )
|
||||
+
|
||||
+ master.run_command(
|
||||
+ [
|
||||
+ "ipa", "automountmap-add",
|
||||
+ "baltimore",
|
||||
+ "auto.share"
|
||||
+ ]
|
||||
+ )
|
||||
+
|
||||
+ master.run_command(
|
||||
+ [
|
||||
+ "ipa", "automountmap-add-indirect",
|
||||
+ "baltimore",
|
||||
+ "--parentmap=auto.share",
|
||||
+ "--mount=sub",
|
||||
+ "auto.man",
|
||||
+ ]
|
||||
+ )
|
||||
+
|
||||
+ master.run_command(
|
||||
+ [
|
||||
+ "ipa", "automountkey-add",
|
||||
+ "baltimore",
|
||||
+ "auto.master",
|
||||
+ "--key=/share",
|
||||
+ "--info=auto.share",
|
||||
+ ]
|
||||
)
|
||||
|
||||
|
||||
@@ -288,12 +318,24 @@ def run_migrate(
|
||||
return result
|
||||
|
||||
|
||||
-class TestIPAMigrateScenario1(IntegrationTest):
|
||||
+@pytest.fixture()
|
||||
+def empty_log_file(request):
|
||||
"""
|
||||
- Tier-1 tests for ipa-migrate tool with DNS enabled on
|
||||
- local and remote server
|
||||
+ This fixture empties the log file before ipa-migrate tool
|
||||
+ is run since the log is appended everytime the tool is run.
|
||||
"""
|
||||
+ request.cls.replicas[0].run_command(
|
||||
+ ["truncate", "-s", "0", paths.IPA_MIGRATE_LOG]
|
||||
+ )
|
||||
+ yield
|
||||
|
||||
+
|
||||
+class MigrationTest(IntegrationTest):
|
||||
+ """
|
||||
+ This class will help setup remote IPA server(cls.master)
|
||||
+ and local IPA server(cls.replicas[0]) and it will
|
||||
+ also prepare the remote IPA before migration actually begins.
|
||||
+ """
|
||||
num_replicas = 1
|
||||
num_clients = 1
|
||||
topology = "line"
|
||||
@@ -303,14 +345,14 @@ class TestIPAMigrateScenario1(IntegrationTest):
|
||||
tasks.install_master(cls.master, setup_dns=True, setup_kra=True)
|
||||
prepare_ipa_server(cls.master)
|
||||
tasks.install_client(cls.master, cls.clients[0], nameservers=None)
|
||||
+ tasks.install_master(cls.replicas[0], setup_dns=True, setup_kra=True)
|
||||
|
||||
- def test_remote_server(self):
|
||||
- """
|
||||
- This test installs IPA server instead of replica on
|
||||
- system under test with the same realm and domain name.
|
||||
- """
|
||||
- tasks.install_master(self.replicas[0], setup_dns=True, setup_kra=True)
|
||||
|
||||
+class TestIPAMigrateCLIOptions(MigrationTest):
|
||||
+ """
|
||||
+ Tests to check CLI options for ipa-migrate tool with
|
||||
+ DNS enabled on local and remote server.
|
||||
+ """
|
||||
def test_ipa_migrate_without_kinit_as_admin(self):
|
||||
"""
|
||||
This test checks that ipa-migrate tool displays
|
||||
@@ -417,7 +459,7 @@ class TestIPAMigrateScenario1(IntegrationTest):
|
||||
"""
|
||||
ldif_file = "/tmp/test.ldif"
|
||||
param = ['-x', '-o', ldif_file]
|
||||
- run_migrate(
|
||||
+ result = run_migrate(
|
||||
self.replicas[0],
|
||||
"stage-mode",
|
||||
self.master.hostname,
|
||||
@@ -426,45 +468,21 @@ class TestIPAMigrateScenario1(IntegrationTest):
|
||||
extra_args=param,
|
||||
)
|
||||
assert self.replicas[0].transport.file_exists("/tmp/test.ldif")
|
||||
+ assert result.returncode == 0
|
||||
|
||||
- @pytest.fixture()
|
||||
- def empty_log_file(self):
|
||||
- """
|
||||
- This fixture empties the log file before ipa-migrate tool
|
||||
- is run since the log is appended everytime the tool is run.
|
||||
- """
|
||||
- self.replicas[0].run_command(
|
||||
- ["truncate", "-s", "0", paths.IPA_MIGRATE_LOG]
|
||||
- )
|
||||
- yield
|
||||
-
|
||||
- def test_ipa_sigden_plugin_fail_error(self, empty_log_file):
|
||||
- """
|
||||
- This testcase checks that sidgen plugin fail error is
|
||||
- not seen during migrate prod-mode
|
||||
- """
|
||||
- SIDGEN_ERR_MSG = "SIDGEN task failed: \n"
|
||||
- run_migrate(
|
||||
- self.replicas[0],
|
||||
- "stage-mode",
|
||||
- self.master.hostname,
|
||||
- "cn=Directory Manager",
|
||||
- self.master.config.admin_password,
|
||||
- extra_args=['-x'],
|
||||
- )
|
||||
- error_msg = self.replicas[0].get_file_contents(
|
||||
- paths.IPA_MIGRATE_LOG, encoding="utf-8"
|
||||
- )
|
||||
- assert SIDGEN_ERR_MSG not in error_msg
|
||||
-
|
||||
- def test_ipa_migrate_stage_mode_dry_run(self, empty_log_file):
|
||||
+ def test_ipa_migrate_stage_mode_dry_run(self):
|
||||
"""
|
||||
Test ipa-migrate stage mode with dry-run option
|
||||
+ This test also checks SIDGEN task failure is
|
||||
+ not seen in ipa migrate log.
|
||||
"""
|
||||
tasks.kinit_admin(self.master)
|
||||
tasks.kinit_admin(self.replicas[0])
|
||||
+ SIDGEN_ERR_MSG = "SIDGEN task failed: \n"
|
||||
IPA_MIGRATE_STAGE_DRY_RUN_LOG = "--dryrun=True\n"
|
||||
- IPA_SERVER_UPRGADE_LOG = "Skipping ipa-server-upgrade in dryrun mode.\n"
|
||||
+ IPA_SERVER_UPRGADE_LOG = (
|
||||
+ "Skipping ipa-server-upgrade in dryrun mode.\n"
|
||||
+ )
|
||||
IPA_SKIP_SIDGEN_LOG = "Skipping SIDGEN task in dryrun mode."
|
||||
result = run_migrate(
|
||||
self.replicas[0],
|
||||
@@ -481,6 +499,7 @@ class TestIPAMigrateScenario1(IntegrationTest):
|
||||
assert IPA_MIGRATE_STAGE_DRY_RUN_LOG in install_msg
|
||||
assert IPA_SERVER_UPRGADE_LOG in install_msg
|
||||
assert IPA_SKIP_SIDGEN_LOG in install_msg
|
||||
+ assert SIDGEN_ERR_MSG not in install_msg
|
||||
|
||||
def test_ipa_migrate_prod_mode_dry_run(self, empty_log_file):
|
||||
"""
|
||||
@@ -509,7 +528,7 @@ class TestIPAMigrateScenario1(IntegrationTest):
|
||||
assert IPA_SERVER_UPRGADE_LOG in install_msg
|
||||
assert IPA_SIDGEN_LOG in install_msg
|
||||
|
||||
- def test_ipa_migrate_with_skip_schema_option_dry_run(self, empty_log_file):
|
||||
+ def test_ipa_migrate_skip_schema_dry_run(self, empty_log_file):
|
||||
"""
|
||||
This test checks that ipa-migrate tool works
|
||||
with -S(schema) options in stage mode
|
||||
@@ -532,7 +551,7 @@ class TestIPAMigrateScenario1(IntegrationTest):
|
||||
)
|
||||
assert SKIP_SCHEMA_MSG_LOG in install_msg
|
||||
|
||||
- def test_ipa_migrate_with_skip_config_option_dry_run(self, empty_log_file):
|
||||
+ def test_ipa_migrate_skip_config_dry_run(self, empty_log_file):
|
||||
"""
|
||||
This test checks that ipa-migrate tool works
|
||||
with -C(config) options in stage mode
|
||||
@@ -579,7 +598,7 @@ class TestIPAMigrateScenario1(IntegrationTest):
|
||||
)
|
||||
assert RESET_RANGE_LOG in install_msg
|
||||
|
||||
- def test_ipa_migrate_stage_mode_dry_override_schema(self, empty_log_file):
|
||||
+ def test_ipa_migrate_stage_mode_override_schema(self, empty_log_file):
|
||||
"""
|
||||
This test checks that -O option (override schema) works
|
||||
in dry mode
|
||||
@@ -601,70 +620,6 @@ class TestIPAMigrateScenario1(IntegrationTest):
|
||||
)
|
||||
assert SCHEMA_OVERRIDE_LOG in install_msg
|
||||
|
||||
- def test_ipa_migrate_stage_mode(self, empty_log_file):
|
||||
- """
|
||||
- This test checks that ipa-migrate is successful
|
||||
- in dry run mode
|
||||
- """
|
||||
- tasks.kinit_admin(self.master)
|
||||
- tasks.kinit_admin(self.replicas[0])
|
||||
- MIGRATION_SCHEMA_LOG_MSG = "Migrating schema ...\n"
|
||||
- MIGRATION_CONFIG_LOG_MSG = "Migrating configuration ...\n"
|
||||
- IPA_UPGRADE_LOG_MSG = (
|
||||
- "Running ipa-server-upgrade ... (this may take a while)\n"
|
||||
- )
|
||||
- SIDGEN_TASK_LOG_MSG = "Running SIDGEN task ...\n"
|
||||
- MIGRATION_COMPLETE_LOG_MSG = "Migration complete!\n"
|
||||
- result = run_migrate(
|
||||
- self.replicas[0],
|
||||
- "stage-mode",
|
||||
- self.master.hostname,
|
||||
- "cn=Directory Manager",
|
||||
- self.master.config.admin_password,
|
||||
- extra_args=['-n'],
|
||||
- )
|
||||
- install_msg = self.replicas[0].get_file_contents(
|
||||
- paths.IPA_MIGRATE_LOG, encoding="utf-8"
|
||||
- )
|
||||
- assert result.returncode == 0
|
||||
- assert MIGRATION_SCHEMA_LOG_MSG in install_msg
|
||||
- assert MIGRATION_CONFIG_LOG_MSG in install_msg
|
||||
- assert IPA_UPGRADE_LOG_MSG in install_msg
|
||||
- assert SIDGEN_TASK_LOG_MSG in install_msg
|
||||
- assert MIGRATION_COMPLETE_LOG_MSG in install_msg
|
||||
-
|
||||
- def test_ipa_migrate_prod_mode(self, empty_log_file):
|
||||
- """
|
||||
- This test checks that ipa-migrate is successful
|
||||
- in prod run mode
|
||||
- """
|
||||
- tasks.kinit_admin(self.master)
|
||||
- tasks.kinit_admin(self.replicas[0])
|
||||
- MIGRATION_SCHEMA_LOG_MSG = "Migrating schema ...\n"
|
||||
- MIGRATION_DATABASE_LOG_MSG = (
|
||||
- "Migrating database ... (this may take a while)\n"
|
||||
- )
|
||||
- IPA_UPGRADE_LOG_MSG = (
|
||||
- "Running ipa-server-upgrade ... (this may take a while)\n"
|
||||
- )
|
||||
- SIDGEN_TASK_LOG_MSG = "Running SIDGEN task ...\n"
|
||||
- result = run_migrate(
|
||||
- self.replicas[0],
|
||||
- "prod-mode",
|
||||
- self.master.hostname,
|
||||
- "cn=Directory Manager",
|
||||
- self.master.config.admin_password,
|
||||
- extra_args=['-n'],
|
||||
- )
|
||||
- install_msg = self.replicas[0].get_file_contents(
|
||||
- paths.IPA_MIGRATE_LOG, encoding="utf-8"
|
||||
- )
|
||||
- assert result.returncode == 0
|
||||
- assert MIGRATION_SCHEMA_LOG_MSG in install_msg
|
||||
- assert MIGRATION_DATABASE_LOG_MSG in install_msg
|
||||
- assert IPA_UPGRADE_LOG_MSG in install_msg
|
||||
- assert SIDGEN_TASK_LOG_MSG in install_msg
|
||||
-
|
||||
def test_ipa_migrate_with_bind_pwd_file_option(self, empty_log_file):
|
||||
"""
|
||||
This testcase checks that ipa-migrate tool
|
||||
@@ -801,6 +756,9 @@ class TestIPAMigrateScenario1(IntegrationTest):
|
||||
|
||||
@pytest.fixture()
|
||||
def modify_dns_zone(self):
|
||||
+ """
|
||||
+ This fixture adds dnszone and then removes the zone.
|
||||
+ """
|
||||
zone_name = 'ipatest.test'
|
||||
self.master.run_command(
|
||||
["ipa", "dnszone-add", zone_name, "--force"]
|
||||
@@ -844,6 +802,20 @@ class TestIPAMigrateScenario1(IntegrationTest):
|
||||
assert DNS_LOG2 in install_msg
|
||||
assert DNS_LOG3 in install_msg
|
||||
|
||||
+ def test_ipa_migrate_dns_forwardzone(self):
|
||||
+ """
|
||||
+ This testcase checks that DNS forwardzone is
|
||||
+ also migrated in prod-mode
|
||||
+ """
|
||||
+ zone_name = "forwardzone.test"
|
||||
+ result = self.replicas[0].run_command(
|
||||
+ ["ipa", "dnsforwardzone-show", zone_name]
|
||||
+ )
|
||||
+ assert 'Zone name: {}'.format(zone_name) in result.stdout_text
|
||||
+ assert 'Active zone: True' in result.stdout_text
|
||||
+ assert 'Zone forwarders: 10.11.12.13' in result.stdout_text
|
||||
+ assert 'Forward policy: first' in result.stdout_text
|
||||
+
|
||||
def test_ipa_migrate_version_option(self):
|
||||
"""
|
||||
The -V option has been removed.
|
||||
@@ -922,20 +894,179 @@ class TestIPAMigrateScenario1(IntegrationTest):
|
||||
assert result.returncode == 1
|
||||
assert ERR_MSG in result.stderr_text
|
||||
|
||||
- def test_ipa_hbac_rule_duplication(self):
|
||||
+
|
||||
+class TestIPAMigrationStageMode(MigrationTest):
|
||||
+ """
|
||||
+ Tests for ipa-migrate tool in stage mode
|
||||
+ """
|
||||
+ def test_ipa_migrate_stage_mode(self, empty_log_file):
|
||||
"""
|
||||
- This testcase checks that default hbac rules
|
||||
- are not duplicated on the local server when
|
||||
- ipa-migrate command is run.
|
||||
+ This test checks that ipa-migrate is successful
|
||||
+ in dry run mode
|
||||
"""
|
||||
+ tasks.kinit_admin(self.master)
|
||||
+ tasks.kinit_admin(self.replicas[0])
|
||||
+ MIGRATION_SCHEMA_LOG_MSG = "Migrating schema ...\n"
|
||||
+ MIGRATION_CONFIG_LOG_MSG = "Migrating configuration ...\n"
|
||||
+ IPA_UPGRADE_LOG_MSG = (
|
||||
+ "Running ipa-server-upgrade ... (this may take a while)\n"
|
||||
+ )
|
||||
+ SIDGEN_TASK_LOG_MSG = "Running SIDGEN task ...\n"
|
||||
+ MIGRATION_COMPLETE_LOG_MSG = "Migration complete!\n"
|
||||
run_migrate(
|
||||
+ self.replicas[0],
|
||||
+ "stage-mode",
|
||||
+ self.master.hostname,
|
||||
+ "cn=Directory Manager",
|
||||
+ self.master.config.admin_password,
|
||||
+ extra_args=['-n'],
|
||||
+ )
|
||||
+ install_msg = self.replicas[0].get_file_contents(
|
||||
+ paths.IPA_MIGRATE_LOG, encoding="utf-8"
|
||||
+ )
|
||||
+ assert MIGRATION_SCHEMA_LOG_MSG in install_msg
|
||||
+ assert MIGRATION_CONFIG_LOG_MSG in install_msg
|
||||
+ assert IPA_UPGRADE_LOG_MSG in install_msg
|
||||
+ assert SIDGEN_TASK_LOG_MSG in install_msg
|
||||
+ assert MIGRATION_COMPLETE_LOG_MSG in install_msg
|
||||
+
|
||||
+ def test_ipa_migrate_stage_mode_new_user(self):
|
||||
+ """
|
||||
+ This testcase checks that when a new user is added and
|
||||
+ ipa-migrate is run in stage-mode, uid/gid of the
|
||||
+ migrated user is not preserved i.e we have different
|
||||
+ uid/gid for user on remote and local IPA server.
|
||||
+ """
|
||||
+ username = 'testuser4'
|
||||
+ base_dn = str(self.master.domain.basedn)
|
||||
+ LOG_MSG1 = (
|
||||
+ "DEBUG Resetting the DNA range for new entry: "
|
||||
+ "uid={},cn=users,cn=accounts,{}\n"
|
||||
+ ).format(username, base_dn)
|
||||
+ install_msg = self.replicas[0].get_file_contents(
|
||||
+ paths.IPA_MIGRATE_LOG, encoding="utf-8"
|
||||
+ )
|
||||
+ assert LOG_MSG1 not in install_msg
|
||||
+ tasks.clear_sssd_cache(self.master)
|
||||
+ self.master.run_command(['ipa', 'user-show', username])
|
||||
+ cmd1 = self.master.run_command(['id', username])
|
||||
+ tasks.clear_sssd_cache(self.replicas[0])
|
||||
+ self.replicas[0].run_command(['ipa', 'user-show', username])
|
||||
+ cmd2 = self.replicas[0].run_command(['id', username])
|
||||
+ assert cmd1.stdout_text != cmd2.stdout_text
|
||||
+
|
||||
+
|
||||
+class TestIPAMigrationProdMode(MigrationTest):
|
||||
+ """
|
||||
+ Tests for ipa-migrate tool in prod mode
|
||||
+ """
|
||||
+ def test_ipa_migrate_prod_mode(self, empty_log_file):
|
||||
+ """
|
||||
+ This test checks that ipa-migrate is successful
|
||||
+ in prod run mode
|
||||
+ """
|
||||
+ tasks.kinit_admin(self.master)
|
||||
+ tasks.kinit_admin(self.replicas[0])
|
||||
+ MIGRATION_SCHEMA_LOG_MSG = "Migrating schema ...\n"
|
||||
+ MIGRATION_DATABASE_LOG_MSG = (
|
||||
+ "Migrating database ... (this may take a while)\n"
|
||||
+ )
|
||||
+ IPA_UPGRADE_LOG_MSG = (
|
||||
+ "Running ipa-server-upgrade ... (this may take a while)\n"
|
||||
+ )
|
||||
+ SIDGEN_TASK_LOG_MSG = "Running SIDGEN task ...\n"
|
||||
+ result = run_migrate(
|
||||
self.replicas[0],
|
||||
"prod-mode",
|
||||
self.master.hostname,
|
||||
"cn=Directory Manager",
|
||||
self.master.config.admin_password,
|
||||
- extra_args=['-n']
|
||||
+ extra_args=['-n'],
|
||||
)
|
||||
+ install_msg = self.replicas[0].get_file_contents(
|
||||
+ paths.IPA_MIGRATE_LOG, encoding="utf-8"
|
||||
+ )
|
||||
+ assert result.returncode == 0
|
||||
+ assert MIGRATION_SCHEMA_LOG_MSG in install_msg
|
||||
+ assert MIGRATION_DATABASE_LOG_MSG in install_msg
|
||||
+ assert IPA_UPGRADE_LOG_MSG in install_msg
|
||||
+ assert SIDGEN_TASK_LOG_MSG in install_msg
|
||||
+
|
||||
+ def test_ipa_migrate_prod_mode_hbac_rule(self):
|
||||
+ """
|
||||
+ This testcase checks that hbac rule is migrated from
|
||||
+ remote server to local server in prod mode.
|
||||
+ """
|
||||
+ hbac_rule_name1 = 'test1'
|
||||
+ hbac_rule_name2 = 'testuser_sshd'
|
||||
+ tasks.kinit_admin(self.replicas[0])
|
||||
+ cmd1 = self.replicas[0].run_command(
|
||||
+ ["ipa", "hbacrule-find", hbac_rule_name1])
|
||||
+ cmd2 = self.replicas[0].run_command(
|
||||
+ ["ipa", "hbacrule-find", hbac_rule_name2])
|
||||
+ assert hbac_rule_name1 in cmd1.stdout_text
|
||||
+ assert hbac_rule_name2 in cmd2.stdout_text
|
||||
+
|
||||
+ def test_ipa_migrate_prod_mode_sudo_rule(self):
|
||||
+ """
|
||||
+ This testcase checks that sudo cmd and rules are
|
||||
+ migrated from remote server to local server in prod mode.
|
||||
+ """
|
||||
+ sudorule = 'readfiles'
|
||||
+ sudocmd = '/usr/bin/less'
|
||||
+ tasks.kinit_admin(self.replicas[0])
|
||||
+ cmd1 = self.replicas[0].run_command(
|
||||
+ ["ipa", "sudorule-find", sudorule])
|
||||
+ cmd2 = self.replicas[0].run_command(
|
||||
+ ["ipa", "sudocmd-find", sudocmd])
|
||||
+ assert 'Rule name: readfiles\n' in cmd1.stdout_text
|
||||
+ assert 'Sudo Command: /usr/bin/less\n' in cmd2.stdout_text
|
||||
+
|
||||
+ def test_ipa_migrate_prod_mode_new_user_sid(self):
|
||||
+ """
|
||||
+ This testcase checks that in prod-mode uid/gid of the
|
||||
+ migrated user is preserved i.e we have same
|
||||
+ uid/gid for user on remote and local IPA server.
|
||||
+ """
|
||||
+ username = 'testuser4'
|
||||
+ tasks.clear_sssd_cache(self.master)
|
||||
+ result1 = self.master.run_command(['id', username])
|
||||
+ tasks.clear_sssd_cache(self.replicas[0])
|
||||
+ result2 = self.replicas[0].run_command(['id', username])
|
||||
+ assert result1.stdout_text == result2.stdout_text
|
||||
+
|
||||
+ def test_check_vault_is_not_migrated(self):
|
||||
+ """
|
||||
+ This testcase checks that vault is
|
||||
+ not migrated
|
||||
+ """
|
||||
+ vault_name = "testvault"
|
||||
+ CMD_OUTPUT = "Number of entries returned 0"
|
||||
+ cmd = self.replicas[0].run_command(
|
||||
+ ["ipa", "vault-find", vault_name], raiseonerr=False)
|
||||
+ assert cmd.returncode != 0
|
||||
+ assert CMD_OUTPUT in cmd.stdout_text
|
||||
+
|
||||
+ def test_ipa_migrate_subids(self):
|
||||
+ """
|
||||
+ This testcase checks that subids for users are migrated
|
||||
+ to the local server from the remote server
|
||||
+ """
|
||||
+ user_name = 'admin'
|
||||
+ CMD_MSG = "1 subordinate id matched"
|
||||
+ cmd = self.replicas[0].run_command(
|
||||
+ ['ipa', 'subid-find',
|
||||
+ '--owner', user_name]
|
||||
+ )
|
||||
+ assert cmd.returncode == 0
|
||||
+ assert CMD_MSG in cmd.stdout_text
|
||||
+
|
||||
+ def test_ipa_hbac_rule_duplication(self):
|
||||
+ """
|
||||
+ This testcase checks that default hbac rules
|
||||
+ are not duplicated on the local server when
|
||||
+ ipa-migrate command is run.
|
||||
+ """
|
||||
result = self.replicas[0].run_command(
|
||||
['ipa', 'hbacrule-find']
|
||||
)
|
||||
@@ -946,3 +1077,192 @@ class TestIPAMigrateScenario1(IntegrationTest):
|
||||
count = Counter(line)
|
||||
assert count.get('Rule name: allow_all') < 2
|
||||
assert count.get('Rule name: allow_systemd-user') < 2
|
||||
+
|
||||
+ def test_ipa_migrate_otptoken(self):
|
||||
+ """
|
||||
+ This testcase checks that the otptoken
|
||||
+ is migrated for the user.
|
||||
+ """
|
||||
+ owner = "testuser1"
|
||||
+ CMD_OUTPUT = "1 OTP token matched"
|
||||
+ result = self.replicas[0].run_command([
|
||||
+ "ipa", "otptoken-find"
|
||||
+ ])
|
||||
+ assert CMD_OUTPUT in result.stdout_text
|
||||
+ assert 'Type: TOTP' in result.stdout_text
|
||||
+ assert 'Owner: {}'.format(owner) in result.stdout_text
|
||||
+
|
||||
+ def test_ipa_migrate_check_passkey_config(self):
|
||||
+ """
|
||||
+ This testcase checks that passkey config
|
||||
+ is migrated
|
||||
+ """
|
||||
+ CMD_OUTPUT = "Require user verification: False"
|
||||
+ result = self.replicas[0].run_command([
|
||||
+ "ipa", "passkeyconfig-show"
|
||||
+ ])
|
||||
+ assert CMD_OUTPUT in result.stdout_text
|
||||
+
|
||||
+ def test_ipa_migrate_check_service_status(self):
|
||||
+ """
|
||||
+ This testcase checks that ipactl and sssd
|
||||
+ services are running post ipa-migrate tool
|
||||
+ successful runs completed
|
||||
+ """
|
||||
+ cmd1 = self.replicas[0].run_command([
|
||||
+ "ipactl", "status"
|
||||
+ ])
|
||||
+ assert cmd1.returncode == 0
|
||||
+ cmd2 = self.replicas[0].run_command([
|
||||
+ "systemctl", "status", "sssd"
|
||||
+ ])
|
||||
+ assert cmd2.returncode == 0
|
||||
+
|
||||
+ def test_custom_idrange_is_migrated(self):
|
||||
+ """
|
||||
+ This testcase checks that custom idrange is migrated
|
||||
+ from remote server to local server in production
|
||||
+ mode.
|
||||
+ """
|
||||
+ range_name = "testrange"
|
||||
+ CMD_OUTPUT = (
|
||||
+ "---------------\n"
|
||||
+ "1 range matched\n"
|
||||
+ "---------------\n"
|
||||
+ " Range name: testrange\n"
|
||||
+ " First Posix ID of the range: 10000\n"
|
||||
+ " Number of IDs in the range: 10000\n"
|
||||
+ " First RID of the corresponding RID range: 300000\n"
|
||||
+ " First RID of the secondary RID range: 400000\n"
|
||||
+ " Range type: local domain range\n"
|
||||
+ "----------------------------\n"
|
||||
+ "Number of entries returned 1\n"
|
||||
+ "----------------------------\n"
|
||||
+ )
|
||||
+ cmd = self.replicas[0].run_command(
|
||||
+ ["ipa", "idrange-find", range_name])
|
||||
+ assert CMD_OUTPUT in cmd.stdout_text
|
||||
+
|
||||
+ def test_automountlocation_is_migrated(self):
|
||||
+ """
|
||||
+ This testcase checks that automount location/maps
|
||||
+ and keys are migrated.
|
||||
+ """
|
||||
+ base_dn = str(self.master.domain.basedn)
|
||||
+ automount_cn = "automount"
|
||||
+ loc_name = "baltimore"
|
||||
+ auto_map_name = "auto.share"
|
||||
+ DEBUG_LOG = (
|
||||
+ "Added entry: cn={},cn={},{}\n"
|
||||
+ ).format(loc_name, automount_cn, base_dn)
|
||||
+ CMD1_OUTPUT = (
|
||||
+ " Location: baltimore\n"
|
||||
+ )
|
||||
+ CMD2_OUTPUT = (
|
||||
+ " Map: auto.share\n"
|
||||
+ )
|
||||
+ CMD3_OUTPUT = (
|
||||
+ "-----------------------\n"
|
||||
+ "1 automount key matched\n"
|
||||
+ "-----------------------\n"
|
||||
+ " Key: sub\n"
|
||||
+ " Mount information: -fstype=autofs ldap:auto.man\n"
|
||||
+ )
|
||||
+ cmd1 = self.replicas[0].run_command(
|
||||
+ ["ipa", "automountlocation-show", loc_name])
|
||||
+ cmd2 = self.replicas[0].run_command(
|
||||
+ ["ipa", "automountmap-find", loc_name])
|
||||
+ cmd3 = self.replicas[0].run_command(
|
||||
+ ["ipa", "automountkey-find", loc_name, auto_map_name]
|
||||
+ )
|
||||
+ install_msg = self.replicas[0].get_file_contents(
|
||||
+ paths.IPA_MIGRATE_LOG, encoding="utf-8"
|
||||
+ )
|
||||
+ assert CMD1_OUTPUT in cmd1.stdout_text
|
||||
+ assert CMD2_OUTPUT in cmd2.stdout_text
|
||||
+ assert CMD3_OUTPUT in cmd3.stdout_text
|
||||
+ assert DEBUG_LOG in install_msg
|
||||
+
|
||||
+
|
||||
+class TestIPAMigrationWithADtrust(IntegrationTest):
|
||||
+ """
|
||||
+ Test for ipa-migrate tool with IPA Master having trust setup
|
||||
+ with Windows AD.
|
||||
+ """
|
||||
+ topology = "line"
|
||||
+ num_ad_domains = 1
|
||||
+ num_replicas = 1
|
||||
+
|
||||
+ @classmethod
|
||||
+ def install(cls, mh):
|
||||
+ tasks.install_master(
|
||||
+ cls.master, setup_dns=True, extra_args=['--no-dnssec-validation']
|
||||
+ )
|
||||
+ cls.ad = cls.ads[0]
|
||||
+ cls.ad_domain = cls.ad.domain.name
|
||||
+ tasks.install_adtrust(cls.master)
|
||||
+ tasks.configure_dns_for_trust(cls.master, cls.ad)
|
||||
+ tasks.establish_trust_with_ad(cls.master, cls.ad.domain.name)
|
||||
+
|
||||
+ def test_install_local_server(self):
|
||||
+ """
|
||||
+ This test installs local IPA Server() i.e new IPA server with
|
||||
+ the same realm and domain name that will receive the migration data.
|
||||
+ """
|
||||
+ tasks.install_master(
|
||||
+ self.replicas[0], setup_dns=True,
|
||||
+ extra_args=['--no-dnssec-validation']
|
||||
+ )
|
||||
+ tasks.install_adtrust(self.replicas[0])
|
||||
+
|
||||
+ def test_check_ad_attributes_migrate_prod_mode(self):
|
||||
+ """
|
||||
+ This test checks that IPA-AD trust related attributes
|
||||
+ are migrated to local server.
|
||||
+ """
|
||||
+ result = run_migrate(
|
||||
+ self.replicas[0],
|
||||
+ "prod-mode",
|
||||
+ self.master.hostname,
|
||||
+ "cn=Directory Manager",
|
||||
+ self.master.config.admin_password,
|
||||
+ extra_args=['-n']
|
||||
+ )
|
||||
+ assert result.returncode == 0
|
||||
+ trust1 = self.master.run_command(
|
||||
+ ['ipa', 'trust-show', self.ad_domain]
|
||||
+ ).stdout_text
|
||||
+ trust2 = self.replicas[0].run_command(
|
||||
+ ['ipa', 'trust-show', self.ad_domain]).stdout_text
|
||||
+ assert trust1 == trust2
|
||||
+
|
||||
+ def test_check_domain_sid_is_migrated(self):
|
||||
+ """
|
||||
+ This testcase checks that domain sid is
|
||||
+ migrated from a remote server having trust with AD
|
||||
+ to local server and is displayed in the
|
||||
+ ipa trustconfig-show command
|
||||
+ """
|
||||
+ regexp = (r'Security Identifier: (.*)$')
|
||||
+ cmd1 = self.master.run_command(["ipa", "trustconfig-show"])
|
||||
+ sid1 = re.findall(regexp, cmd1.stdout_text, re.MULTILINE)
|
||||
+ cmd2 = self.replicas[0].run_command(
|
||||
+ ["ipa", "trustconfig-show"]
|
||||
+ )
|
||||
+ sid2 = re.findall(regexp, cmd2.stdout_text, re.MULTILINE)
|
||||
+ assert sid1 == sid2
|
||||
+
|
||||
+ def test_check_ad_idrange_is_migrated(self):
|
||||
+ """
|
||||
+ This testcase checks AD idrange is migrated
|
||||
+ from remote IPA server having trust with AD
|
||||
+ to local IPA server
|
||||
+ """
|
||||
+ ad_domain_name = self.ad.domain.name.upper()
|
||||
+ cmd1 = self.master.run_command(
|
||||
+ ["ipa", "idrange-show", ad_domain_name + "_id_range"]
|
||||
+ )
|
||||
+ cmd2 = self.replicas[0].run_command(
|
||||
+ ["ipa", "idrange-show", ad_domain_name + "_id_range"]
|
||||
+ )
|
||||
+ assert cmd1.stdout_text == cmd2.stdout_text
|
||||
--
|
||||
2.47.0
|
||||
|
@ -0,0 +1,34 @@
|
||||
From c64c098e1d0ae492499caa83a1b73532da511f84 Mon Sep 17 00:00:00 2001
|
||||
From: Carla Martinez <carlmart@redhat.com>
|
||||
Date: Tue, 29 Oct 2024 15:23:55 +0100
|
||||
Subject: [PATCH] Fix: 'Organization' field in Okta not required
|
||||
|
||||
Although the 'Organization' field is not required
|
||||
when using the Okta template, the WebUI requires it
|
||||
in order to create a new IDP. If this is not provided,
|
||||
an error is shown.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9687
|
||||
Signed-off-by: Carla Martinez <carlmart@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
---
|
||||
install/ui/src/freeipa/idp.js | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/install/ui/src/freeipa/idp.js b/install/ui/src/freeipa/idp.js
|
||||
index ada09c0754f5a51575831e127deb81d1f27f44d1..04daad591a8e94ea9b8c146c12e0c84aaad6cee4 100644
|
||||
--- a/install/ui/src/freeipa/idp.js
|
||||
+++ b/install/ui/src/freeipa/idp.js
|
||||
@@ -41,7 +41,7 @@ idp.templates = [
|
||||
fields: ['ipaidporg']},
|
||||
{ value: 'okta',
|
||||
label: text.get('@i18n:objects.idp.template_okta'),
|
||||
- fields: ['ipaidporg', 'ipaidpbaseurl']}
|
||||
+ fields: ['ipaidpbaseurl']}
|
||||
];
|
||||
|
||||
|
||||
--
|
||||
2.47.0
|
||||
|
@ -1,335 +0,0 @@
|
||||
From 3bba254ccdcf9b62fdd8a6d71baecf37c97c300c Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Mon, 3 Apr 2023 08:37:28 +0200
|
||||
Subject: [PATCH] ipatests: mark known failures for autoprivategroup
|
||||
|
||||
Two tests have known issues in test_trust.py with sssd 2.8.2+:
|
||||
- TestNonPosixAutoPrivateGroup::test_idoverride_with_auto_private_group
|
||||
(when called with the "hybrid" parameter)
|
||||
- TestPosixAutoPrivateGroup::test_only_uid_number_auto_private_group_default
|
||||
(when called with the "true" parameter)
|
||||
|
||||
Related: https://pagure.io/freeipa/issue/9295
|
||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
---
|
||||
ipatests/test_integration/test_trust.py | 17 ++++++++++++-----
|
||||
1 file changed, 12 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/ipatests/test_integration/test_trust.py b/ipatests/test_integration/test_trust.py
|
||||
index 0d5b71cb0..12f000c1a 100644
|
||||
--- a/ipatests/test_integration/test_trust.py
|
||||
+++ b/ipatests/test_integration/test_trust.py
|
||||
@@ -1154,11 +1154,15 @@ class TestNonPosixAutoPrivateGroup(BaseTestTrust):
|
||||
self.gid_override
|
||||
):
|
||||
self.mod_idrange_auto_private_group(type)
|
||||
- (uid, gid) = self.get_user_id(self.clients[0], nonposixuser)
|
||||
- assert (uid == self.uid_override and gid == self.gid_override)
|
||||
+ sssd_version = tasks.get_sssd_version(self.clients[0])
|
||||
+ bad_version = sssd_version >= tasks.parse_version("2.8.2")
|
||||
+ cond = (type == 'hybrid') and bad_version
|
||||
+ with xfail_context(condition=cond,
|
||||
+ reason="https://pagure.io/freeipa/issue/9295"):
|
||||
+ (uid, gid) = self.get_user_id(self.clients[0], nonposixuser)
|
||||
+ assert (uid == self.uid_override and gid == self.gid_override)
|
||||
test_group = self.clients[0].run_command(
|
||||
["id", nonposixuser]).stdout_text
|
||||
- # version = tasks.get_sssd_version(self.clients[0])
|
||||
with xfail_context(type == "hybrid",
|
||||
'https://github.com/SSSD/sssd/issues/5989'):
|
||||
assert "domain users@{0}".format(self.ad_domain) in test_group
|
||||
@@ -1232,8 +1236,11 @@ class TestPosixAutoPrivateGroup(BaseTestTrust):
|
||||
posixuser = "testuser1@%s" % self.ad_domain
|
||||
self.mod_idrange_auto_private_group(type)
|
||||
if type == "true":
|
||||
- (uid, gid) = self.get_user_id(self.clients[0], posixuser)
|
||||
- assert uid == gid
|
||||
+ sssd_version = tasks.get_sssd_version(self.clients[0])
|
||||
+ with xfail_context(sssd_version >= tasks.parse_version("2.8.2"),
|
||||
+ "https://pagure.io/freeipa/issue/9295"):
|
||||
+ (uid, gid) = self.get_user_id(self.clients[0], posixuser)
|
||||
+ assert uid == gid
|
||||
else:
|
||||
for host in [self.master, self.clients[0]]:
|
||||
result = host.run_command(['id', posixuser], raiseonerr=False)
|
||||
--
|
||||
2.44.0
|
||||
|
||||
From ed2a8eb0cefadfe0544074114facfef381349ae0 Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Feb 12 2024 10:43:39 +0000
|
||||
Subject: ipatests: add xfail for autoprivate group test with override
|
||||
|
||||
|
||||
Because of SSSD issue 7169, secondary groups are not
|
||||
retrieved when autoprivate group is set and an idoverride
|
||||
replaces the user's primary group.
|
||||
Mark the known issues as xfail.
|
||||
|
||||
Related: https://github.com/SSSD/sssd/issues/7169
|
||||
|
||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Anuja More <amore@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/ipatests/test_integration/test_trust.py b/ipatests/test_integration/test_trust.py
|
||||
index 3b9f0fb..2b94514 100644
|
||||
--- a/ipatests/test_integration/test_trust.py
|
||||
+++ b/ipatests/test_integration/test_trust.py
|
||||
@@ -1164,8 +1164,12 @@ class TestNonPosixAutoPrivateGroup(BaseTestTrust):
|
||||
assert (uid == self.uid_override and gid == self.gid_override)
|
||||
test_group = self.clients[0].run_command(
|
||||
["id", nonposixuser]).stdout_text
|
||||
- with xfail_context(type == "hybrid",
|
||||
- 'https://github.com/SSSD/sssd/issues/5989'):
|
||||
+ cond2 = ((type == 'false'
|
||||
+ and sssd_version >= tasks.parse_version("2.9.4"))
|
||||
+ or type == 'hybrid')
|
||||
+ with xfail_context(cond2,
|
||||
+ 'https://github.com/SSSD/sssd/issues/5989 '
|
||||
+ 'and 7169'):
|
||||
assert "domain users@{0}".format(self.ad_domain) in test_group
|
||||
|
||||
@pytest.mark.parametrize('type', ['hybrid', 'true', "false"])
|
||||
@@ -1287,5 +1291,9 @@ class TestPosixAutoPrivateGroup(BaseTestTrust):
|
||||
assert(uid == self.uid_override
|
||||
and gid == self.gid_override)
|
||||
result = self.clients[0].run_command(['id', posixuser])
|
||||
- assert "10047(testgroup@{0})".format(
|
||||
- self.ad_domain) in result.stdout_text
|
||||
+ sssd_version = tasks.get_sssd_version(self.clients[0])
|
||||
+ bad_version = sssd_version >= tasks.parse_version("2.9.4")
|
||||
+ with xfail_context(bad_version and type in ('false', 'hybrid'),
|
||||
+ "https://github.com/SSSD/sssd/issues/7169"):
|
||||
+ assert "10047(testgroup@{0})".format(
|
||||
+ self.ad_domain) in result.stdout_text
|
||||
|
||||
From d5392300d77170ea3202ee80690ada8bf81b60b5 Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Feb 12 2024 10:44:47 +0000
|
||||
Subject: ipatests: remove xfail thanks to sssd 2.9.4
|
||||
|
||||
|
||||
SSSD 2.9.4 fixes some issues related to auto-private-group
|
||||
|
||||
Related: https://pagure.io/freeipa/issue/9295
|
||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Anuja More <amore@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/ipatests/test_integration/test_trust.py b/ipatests/test_integration/test_trust.py
|
||||
index 12f000c..3b9f0fb 100644
|
||||
--- a/ipatests/test_integration/test_trust.py
|
||||
+++ b/ipatests/test_integration/test_trust.py
|
||||
@@ -1155,7 +1155,8 @@ class TestNonPosixAutoPrivateGroup(BaseTestTrust):
|
||||
):
|
||||
self.mod_idrange_auto_private_group(type)
|
||||
sssd_version = tasks.get_sssd_version(self.clients[0])
|
||||
- bad_version = sssd_version >= tasks.parse_version("2.8.2")
|
||||
+ bad_version = (tasks.parse_version("2.8.2") <= sssd_version
|
||||
+ < tasks.parse_version("2.9.4"))
|
||||
cond = (type == 'hybrid') and bad_version
|
||||
with xfail_context(condition=cond,
|
||||
reason="https://pagure.io/freeipa/issue/9295"):
|
||||
@@ -1237,7 +1238,9 @@ class TestPosixAutoPrivateGroup(BaseTestTrust):
|
||||
self.mod_idrange_auto_private_group(type)
|
||||
if type == "true":
|
||||
sssd_version = tasks.get_sssd_version(self.clients[0])
|
||||
- with xfail_context(sssd_version >= tasks.parse_version("2.8.2"),
|
||||
+ bad_version = (tasks.parse_version("2.8.2") <= sssd_version
|
||||
+ < tasks.parse_version("2.9.4"))
|
||||
+ with xfail_context(bad_version,
|
||||
"https://pagure.io/freeipa/issue/9295"):
|
||||
(uid, gid) = self.get_user_id(self.clients[0], posixuser)
|
||||
assert uid == gid
|
||||
|
||||
From 34d048ede0c439b3a53e02f8ace96ff91aa1609d Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Mar 14 2023 16:50:25 +0000
|
||||
Subject: ipatests: adapt for new automembership fixup behavior
|
||||
|
||||
|
||||
The automembership fixup task now needs to be called
|
||||
with --cleanup argument when the user expects automember
|
||||
to remove user/hosts from automember groups.
|
||||
Update the test to call create a cleanup task equivalent to
|
||||
dsconf plugin automember fixup --cleanup
|
||||
when it is needed.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9313
|
||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/ipatests/test_integration/test_automember.py b/ipatests/test_integration/test_automember.py
|
||||
index 7acd0d7..8b27f4d 100644
|
||||
--- a/ipatests/test_integration/test_automember.py
|
||||
+++ b/ipatests/test_integration/test_automember.py
|
||||
@@ -4,6 +4,7 @@
|
||||
"""This covers tests for automemberfeature."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
+import uuid
|
||||
|
||||
from ipapython.dn import DN
|
||||
|
||||
@@ -211,11 +212,27 @@ class TestAutounmembership(IntegrationTest):
|
||||
# Running automember-build so that user is part of correct group
|
||||
result = self.master.run_command(['ipa', 'automember-rebuild',
|
||||
'--users=%s' % user2])
|
||||
+ assert msg in result.stdout_text
|
||||
+
|
||||
+ # The additional --cleanup argument is required
|
||||
+ cleanup_ldif = (
|
||||
+ "dn: cn={cn},cn=automember rebuild membership,"
|
||||
+ "cn=tasks,cn=config\n"
|
||||
+ "changetype: add\n"
|
||||
+ "objectclass: top\n"
|
||||
+ "objectclass: extensibleObject\n"
|
||||
+ "basedn: cn=users,cn=accounts,{suffix}\n"
|
||||
+ "filter: (uid={user})\n"
|
||||
+ "cleanup: yes\n"
|
||||
+ "scope: sub"
|
||||
+ ).format(cn=str(uuid.uuid4()),
|
||||
+ suffix=str(self.master.domain.basedn),
|
||||
+ user=user2)
|
||||
+ tasks.ldapmodify_dm(self.master, cleanup_ldif)
|
||||
+
|
||||
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)
|
||||
@@ -248,11 +265,27 @@ class TestAutounmembership(IntegrationTest):
|
||||
result = self.master.run_command(
|
||||
['ipa', 'automember-rebuild', '--hosts=%s' % host2]
|
||||
)
|
||||
+ assert msg in result.stdout_text
|
||||
+
|
||||
+ # The additional --cleanup argument is required
|
||||
+ cleanup_ldif = (
|
||||
+ "dn: cn={cn},cn=automember rebuild membership,"
|
||||
+ "cn=tasks,cn=config\n"
|
||||
+ "changetype: add\n"
|
||||
+ "objectclass: top\n"
|
||||
+ "objectclass: extensibleObject\n"
|
||||
+ "basedn: cn=computers,cn=accounts,{suffix}\n"
|
||||
+ "filter: (fqdn={fqdn})\n"
|
||||
+ "cleanup: yes\n"
|
||||
+ "scope: sub"
|
||||
+ ).format(cn=str(uuid.uuid4()),
|
||||
+ suffix=str(self.master.domain.basedn),
|
||||
+ fqdn=host2)
|
||||
+ tasks.ldapmodify_dm(self.master, cleanup_ldif)
|
||||
+
|
||||
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)
|
||||
|
||||
From 9b777390fbb6d4c683bf7d3e5f74d5443209b1d5 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Fri, 24 Mar 2023 08:15:00 +0200
|
||||
Subject: [PATCH] test_xmlrpc: adopt to automember plugin message changes in
|
||||
389-ds
|
||||
|
||||
Another change in automember plugin messaging that breaks FreeIPA tests.
|
||||
Use common substring to match.
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipatests/test_xmlrpc/xmlrpc_test.py | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ipatests/test_xmlrpc/xmlrpc_test.py b/ipatests/test_xmlrpc/xmlrpc_test.py
|
||||
index cf11721bfca..5fe1245dc65 100644
|
||||
--- a/ipatests/test_xmlrpc/xmlrpc_test.py
|
||||
+++ b/ipatests/test_xmlrpc/xmlrpc_test.py
|
||||
@@ -64,7 +64,7 @@ def test(xs):
|
||||
|
||||
# Matches an automember task finish message
|
||||
fuzzy_automember_message = Fuzzy(
|
||||
- r'^Automember rebuild task finished\. Processed \(\d+\) entries\.$'
|
||||
+ r'^Automember rebuild task finished\. Processed \(\d+\) entries'
|
||||
)
|
||||
|
||||
# Matches trusted domain GUID, like u'463bf2be-3456-4a57-979e-120304f2a0eb'
|
||||
From 8e8b97a2251329aec9633a5c7c644bc5034bc8c2 Mon Sep 17 00:00:00 2001
|
||||
From: Sudhir Menon <sumenon@redhat.com>
|
||||
Date: Wed, 20 Mar 2024 14:29:46 +0530
|
||||
Subject: [PATCH] ipatests: Fixes for test_ipahealthcheck_ipansschainvalidation
|
||||
testcases.
|
||||
|
||||
Currently the test is using IPA_NSSDB_PWDFILE_TXT which is /etc/ipa/nssdb/pwdfile.txt
|
||||
which causes error in STIG mode.
|
||||
|
||||
[root@master slapd-TESTRELM-TEST]# certutil -M -n 'TESTRELM.TEST IPA CA' -t ',,' -d . -f /etc/ipa/nssdb/pwdfile.txt
|
||||
Incorrect password/PIN entered.
|
||||
|
||||
Hence modified the test to include paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE/pwd.txt.
|
||||
|
||||
Signed-off-by: Sudhir Menon <sumenon@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipatests/test_integration/test_ipahealthcheck.py | 11 ++++++-----
|
||||
1 file changed, 6 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py
|
||||
index 8aae9fad776..a96de7088aa 100644
|
||||
--- a/ipatests/test_integration/test_ipahealthcheck.py
|
||||
+++ b/ipatests/test_integration/test_ipahealthcheck.py
|
||||
@@ -2731,17 +2731,18 @@ def remove_server_cert(self):
|
||||
Fixture to remove Server cert and revert the change.
|
||||
"""
|
||||
instance = realm_to_serverid(self.master.domain.realm)
|
||||
+ instance_dir = paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % instance
|
||||
self.master.run_command(
|
||||
[
|
||||
"certutil",
|
||||
"-L",
|
||||
"-d",
|
||||
- paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % instance,
|
||||
+ instance_dir,
|
||||
"-n",
|
||||
"Server-Cert",
|
||||
"-a",
|
||||
"-o",
|
||||
- paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % instance
|
||||
+ instance_dir
|
||||
+ "/Server-Cert.pem",
|
||||
]
|
||||
)
|
||||
@@ -2760,15 +2761,15 @@ def remove_server_cert(self):
|
||||
[
|
||||
"certutil",
|
||||
"-d",
|
||||
- paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % instance,
|
||||
+ instance_dir,
|
||||
"-A",
|
||||
"-i",
|
||||
- paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % instance
|
||||
+ instance_dir
|
||||
+ "/Server-Cert.pem",
|
||||
"-t",
|
||||
"u,u,u",
|
||||
"-f",
|
||||
- paths.IPA_NSSDB_PWDFILE_TXT,
|
||||
+ "%s/pwdfile.txt" % instance_dir,
|
||||
"-n",
|
||||
"Server-Cert",
|
||||
]
|
@ -0,0 +1,42 @@
|
||||
From baa9fc3e3e2f6b39db5ec465c92dc597cd5399b9 Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Tue, 12 Nov 2024 16:44:46 +0100
|
||||
Subject: [PATCH] ipatests: install master with allow-zone-overlap
|
||||
|
||||
In the IPA to IPA migration tests, install the destination master
|
||||
with --setup-dns --allow-zone-overlap to allow installation
|
||||
even if the zone is already served by the source master.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9697
|
||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Sudhir Menon <sumenon@redhat.com>
|
||||
---
|
||||
ipatests/test_integration/test_ipa_ipa_migration.py | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/ipatests/test_integration/test_ipa_ipa_migration.py b/ipatests/test_integration/test_ipa_ipa_migration.py
|
||||
index d852ca63a6b3a7e7118d66ce1cd9bb98e56f1a73..0c637a0141d95f34f951c60a9648adf8e87eaa63 100644
|
||||
--- a/ipatests/test_integration/test_ipa_ipa_migration.py
|
||||
+++ b/ipatests/test_integration/test_ipa_ipa_migration.py
|
||||
@@ -345,7 +345,8 @@ class MigrationTest(IntegrationTest):
|
||||
tasks.install_master(cls.master, setup_dns=True, setup_kra=True)
|
||||
prepare_ipa_server(cls.master)
|
||||
tasks.install_client(cls.master, cls.clients[0], nameservers=None)
|
||||
- tasks.install_master(cls.replicas[0], setup_dns=True, setup_kra=True)
|
||||
+ tasks.install_master(cls.replicas[0], setup_dns=True, setup_kra=True,
|
||||
+ extra_args=['--allow-zone-overlap'])
|
||||
|
||||
|
||||
class TestIPAMigrateCLIOptions(MigrationTest):
|
||||
@@ -1211,7 +1212,7 @@ class TestIPAMigrationWithADtrust(IntegrationTest):
|
||||
"""
|
||||
tasks.install_master(
|
||||
self.replicas[0], setup_dns=True,
|
||||
- extra_args=['--no-dnssec-validation']
|
||||
+ extra_args=['--no-dnssec-validation', '--allow-zone-overlap']
|
||||
)
|
||||
tasks.install_adtrust(self.replicas[0])
|
||||
|
||||
--
|
||||
2.47.0
|
||||
|
@ -1,341 +0,0 @@
|
||||
From 0a48726e104282fb40d8f471ebb306bc9134cb0c Mon Sep 17 00:00:00 2001
|
||||
From: Julien Rische <jrische@redhat.com>
|
||||
Date: Tue, 19 Mar 2024 12:24:40 +0100
|
||||
Subject: [PATCH] kdb: fix vulnerability in GCD rules handling
|
||||
|
||||
The initial implementation of MS-SFU by MIT Kerberos was missing some
|
||||
a condition for granting the "forwardable" flag on S4U2Self tickets.
|
||||
Fixing this mistake required to add a special case for the
|
||||
check_allowed_to_delegate() function: if the target service argument is
|
||||
NULL, then it means the KDC is probing for general constrained
|
||||
delegation rules, not actually checking a specific S4U2Proxy request.
|
||||
|
||||
In commit e86807b5, the behavior of ipadb_match_acl() was modified to
|
||||
match the changes from upstream MIT Kerberos a441fbe3. However, a
|
||||
mistake resulted in this mechanism to apply in cases where target
|
||||
service argument is set AND unset. This results in S4U2Proxy requests to
|
||||
be accepted regardless of the fact there is a matching service
|
||||
delegation rule or not.
|
||||
|
||||
This vulnerability does not affect services having RBCD (resource-based
|
||||
constrained delegation) rules.
|
||||
|
||||
This fixes CVE-2024-2698
|
||||
|
||||
Signed-off-by: Julien Rische <jrische@redhat.com>
|
||||
---
|
||||
daemons/ipa-kdb/README.s4u2proxy.txt | 19 ++-
|
||||
daemons/ipa-kdb/ipa_kdb_delegation.c | 191 +++++++++++++++------------
|
||||
2 files changed, 118 insertions(+), 92 deletions(-)
|
||||
|
||||
diff --git a/daemons/ipa-kdb/README.s4u2proxy.txt b/daemons/ipa-kdb/README.s4u2proxy.txt
|
||||
index 254fcc4d1..ab34aff36 100644
|
||||
--- a/daemons/ipa-kdb/README.s4u2proxy.txt
|
||||
+++ b/daemons/ipa-kdb/README.s4u2proxy.txt
|
||||
@@ -12,9 +12,7 @@ much more easily managed.
|
||||
|
||||
The grouping mechanism has been built so that lookup is highly optimized
|
||||
and is basically reduced to a single search that uses the derefernce
|
||||
-control. Speed is very important in this case because KDC operations
|
||||
-time out very quickly and unless we add a caching layer in ipa-kdb we
|
||||
-must keep the number of searches down to avoid client timeouts.
|
||||
+control.
|
||||
|
||||
The grouping mechanism is very simple a groupOfPrincipals object is
|
||||
introduced, this Auxiliary class have a single optional attribute called
|
||||
@@ -112,8 +110,7 @@ kinit -kt /etc/httpd/conf/ipa.keytab HTTP/ipaserver.example.com
|
||||
kvno -U admin HTTP/ipaserver.example.com
|
||||
|
||||
# Perform S4U2Proxy
|
||||
-kvno -k /etc/httpd/conf/ipa.keytab -U admin -P HTTP/ipaserver.example.com
|
||||
-ldap/ipaserver.example.com
|
||||
+kvno -U admin -P ldap/ipaserver.example.com
|
||||
|
||||
|
||||
If this works it means you successfully impersonated the admin user with
|
||||
@@ -125,6 +122,18 @@ modprinc -ok_to_auth_as_delegate HTTP/ipaserver.example.com
|
||||
Simo.
|
||||
|
||||
|
||||
+If IPA is compiled with krb5 1.20 and newer (KDB DAL >= 9), then the
|
||||
+behavior of S4U2Self changes: S4U2Self TGS-REQs produce forwardable
|
||||
+tickets for all requesters, except if the requester principal is set as
|
||||
+the proxy (impersonating service) in at least one `servicedelegation`
|
||||
+rule. In this case, even if the rule has no target, the KDC will
|
||||
+response to S4U2Self requests with a non-forwardable ticket. Hence,
|
||||
+granting the `ok_to_auth_as_delegate` permission to the proxy service
|
||||
+remains the only way for this service to obtain the evidence ticket
|
||||
+required for general constrained delegation requests if this ticket is
|
||||
+not provided by the client.
|
||||
+
|
||||
+
|
||||
[1]
|
||||
Note that here I use the term proxy in a different way than it is used in
|
||||
the krb interfaces. It may seem a bit confusing but I think people will
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_delegation.c b/daemons/ipa-kdb/ipa_kdb_delegation.c
|
||||
index de82174ad..3581f3c79 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_delegation.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_delegation.c
|
||||
@@ -91,120 +91,110 @@ static bool ipadb_match_member(char *princ, LDAPDerefRes *dres)
|
||||
return false;
|
||||
}
|
||||
|
||||
-static krb5_error_code ipadb_match_acl(krb5_context kcontext,
|
||||
- LDAPMessage *results,
|
||||
- krb5_const_principal client,
|
||||
- krb5_const_principal target)
|
||||
+#if KRB5_KDB_DAL_MAJOR_VERSION >= 9
|
||||
+static krb5_error_code
|
||||
+ipadb_has_acl(krb5_context kcontext, LDAPMessage *ldap_acl, bool *res)
|
||||
{
|
||||
struct ipadb_context *ipactx;
|
||||
- krb5_error_code kerr;
|
||||
- LDAPMessage *lentry;
|
||||
- LDAPDerefRes *deref_results;
|
||||
- LDAPDerefRes *dres;
|
||||
- char *client_princ = NULL;
|
||||
- char *target_princ = NULL;
|
||||
- bool client_missing;
|
||||
- bool client_found;
|
||||
- bool target_found;
|
||||
- bool is_constraint_delegation = false;
|
||||
- size_t nrules = 0;
|
||||
- int ret;
|
||||
+ bool in_res = false;
|
||||
+ krb5_error_code kerr = 0;
|
||||
|
||||
ipactx = ipadb_get_context(kcontext);
|
||||
- if (!ipactx) {
|
||||
+ if (!ipactx)
|
||||
return KRB5_KDB_DBNOTINITED;
|
||||
- }
|
||||
|
||||
- if ((client != NULL) && (target != NULL)) {
|
||||
- kerr = krb5_unparse_name(kcontext, client, &client_princ);
|
||||
- if (kerr != 0) {
|
||||
- goto done;
|
||||
- }
|
||||
- kerr = krb5_unparse_name(kcontext, target, &target_princ);
|
||||
- if (kerr != 0) {
|
||||
- goto done;
|
||||
- }
|
||||
- } else {
|
||||
- is_constraint_delegation = true;
|
||||
+ switch (ldap_count_entries(ipactx->lcontext, ldap_acl)) {
|
||||
+ case 0:
|
||||
+ break;
|
||||
+ case -1:
|
||||
+ kerr = EINVAL;
|
||||
+ goto end;
|
||||
+ default:
|
||||
+ in_res = true;
|
||||
+ goto end;
|
||||
}
|
||||
|
||||
- lentry = ldap_first_entry(ipactx->lcontext, results);
|
||||
- if (!lentry) {
|
||||
- kerr = ENOENT;
|
||||
- goto done;
|
||||
- }
|
||||
+end:
|
||||
+ if (res)
|
||||
+ *res = in_res;
|
||||
+
|
||||
+ return kerr;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+static krb5_error_code
|
||||
+ipadb_match_acl(krb5_context kcontext, LDAPMessage *ldap_acl,
|
||||
+ krb5_const_principal client, krb5_const_principal target)
|
||||
+{
|
||||
+ struct ipadb_context *ipactx;
|
||||
+ LDAPMessage *rule;
|
||||
+ LDAPDerefRes *acis, *aci;
|
||||
+ char *client_princ = NULL, *target_princ= NULL;
|
||||
+ bool client_missing, client_found, target_found;
|
||||
+ int lerr;
|
||||
+ krb5_error_code kerr;
|
||||
+
|
||||
+ ipactx = ipadb_get_context(kcontext);
|
||||
+ if (!ipactx)
|
||||
+ return KRB5_KDB_DBNOTINITED;
|
||||
+
|
||||
+ kerr = krb5_unparse_name(kcontext, client, &client_princ);
|
||||
+ if (kerr)
|
||||
+ goto end;
|
||||
+
|
||||
+ kerr = krb5_unparse_name(kcontext, target, &target_princ);
|
||||
+ if (kerr)
|
||||
+ goto end;
|
||||
|
||||
/* the default is that we fail */
|
||||
- kerr = ENOENT;
|
||||
+ kerr = KRB5KDC_ERR_BADOPTION;
|
||||
|
||||
- while (lentry) {
|
||||
+ for (rule = ldap_first_entry(ipactx->lcontext, ldap_acl);
|
||||
+ rule;
|
||||
+ rule = ldap_next_entry(ipactx->lcontext, rule))
|
||||
+ {
|
||||
/* both client and target must be found in the same ACI */
|
||||
client_missing = true;
|
||||
client_found = false;
|
||||
target_found = false;
|
||||
|
||||
- ret = ipadb_ldap_deref_results(ipactx->lcontext, lentry,
|
||||
- &deref_results);
|
||||
- switch (ret) {
|
||||
+ lerr = ipadb_ldap_deref_results(ipactx->lcontext, rule, &acis);
|
||||
+ switch (lerr) {
|
||||
case 0:
|
||||
- for (dres = deref_results; dres; dres = dres->next) {
|
||||
- nrules++;
|
||||
- if (is_constraint_delegation) {
|
||||
- /*
|
||||
- Microsoft revised the S4U2Proxy rules for forwardable
|
||||
- tickets. All S4U2Proxy operations require forwardable
|
||||
- evidence tickets, but S4U2Self should issue a
|
||||
- forwardable ticket if the requesting service has no
|
||||
- ok-to-auth-as-delegate bit but also no constrained
|
||||
- delegation privileges for traditional S4U2Proxy.
|
||||
- Implement these rules, extending the
|
||||
- check_allowed_to_delegate() DAL method so that the KDC
|
||||
- can ask if a principal has any delegation privileges.
|
||||
-
|
||||
- Since target principal is NULL and client principal is
|
||||
- NULL in this case, we simply calculate number of rules associated
|
||||
- with the server principal to decide whether to deny forwardable bit
|
||||
- */
|
||||
- continue;
|
||||
- }
|
||||
- if (client_found == false &&
|
||||
- strcasecmp(dres->derefAttr, "ipaAllowToImpersonate") == 0) {
|
||||
+ for (aci = acis; aci; aci = aci->next) {
|
||||
+ if (!client_found &&
|
||||
+ 0 == strcasecmp(aci->derefAttr, "ipaAllowToImpersonate"))
|
||||
+ {
|
||||
/* NOTE: client_missing is used to signal that the
|
||||
* attribute was completely missing. This signals that
|
||||
* ANY client is allowed to be impersonated.
|
||||
* This logic is valid only for clients, not for targets */
|
||||
client_missing = false;
|
||||
- client_found = ipadb_match_member(client_princ, dres);
|
||||
+ client_found = ipadb_match_member(client_princ, aci);
|
||||
}
|
||||
- if (target_found == false &&
|
||||
- strcasecmp(dres->derefAttr, "ipaAllowedTarget") == 0) {
|
||||
- target_found = ipadb_match_member(target_princ, dres);
|
||||
+ if (!target_found &&
|
||||
+ 0 == strcasecmp(aci->derefAttr, "ipaAllowedTarget"))
|
||||
+ {
|
||||
+ target_found = ipadb_match_member(target_princ, aci);
|
||||
}
|
||||
}
|
||||
|
||||
- ldap_derefresponse_free(deref_results);
|
||||
+ ldap_derefresponse_free(acis);
|
||||
break;
|
||||
case ENOENT:
|
||||
break;
|
||||
default:
|
||||
- kerr = ret;
|
||||
- goto done;
|
||||
+ kerr = lerr;
|
||||
+ goto end;
|
||||
}
|
||||
|
||||
- if ((client_found == true || client_missing == true) &&
|
||||
- target_found == true) {
|
||||
+ if ((client_found || client_missing) && target_found) {
|
||||
kerr = 0;
|
||||
- goto done;
|
||||
+ goto end;
|
||||
}
|
||||
-
|
||||
- lentry = ldap_next_entry(ipactx->lcontext, lentry);
|
||||
- }
|
||||
-
|
||||
- if (nrules > 0) {
|
||||
- kerr = 0;
|
||||
}
|
||||
|
||||
-done:
|
||||
+end:
|
||||
krb5_free_unparsed_name(kcontext, client_princ);
|
||||
krb5_free_unparsed_name(kcontext, target_princ);
|
||||
return kerr;
|
||||
@@ -223,7 +213,7 @@ krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext,
|
||||
char *srv_principal = NULL;
|
||||
krb5_db_entry *proxy_entry = NULL;
|
||||
struct ipadb_e_data *ied_server, *ied_proxy;
|
||||
- LDAPMessage *res = NULL;
|
||||
+ LDAPMessage *ldap_gcd_acl = NULL;
|
||||
|
||||
if (proxy != NULL) {
|
||||
/* Handle the case where server == proxy, this is allowed in S4U */
|
||||
@@ -261,26 +251,53 @@ krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext,
|
||||
goto done;
|
||||
}
|
||||
|
||||
- kerr = ipadb_get_delegation_acl(kcontext, srv_principal, &res);
|
||||
+ /* Load general constrained delegation rules */
|
||||
+ kerr = ipadb_get_delegation_acl(kcontext, srv_principal, &ldap_gcd_acl);
|
||||
if (kerr) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
- kerr = ipadb_match_acl(kcontext, res, client, proxy);
|
||||
- if (kerr) {
|
||||
- goto done;
|
||||
+#if KRB5_KDB_DAL_MAJOR_VERSION >= 9
|
||||
+ /*
|
||||
+ * Microsoft revised the S4U2Proxy rules for forwardable tickets. All
|
||||
+ * S4U2Proxy operations require forwardable evidence tickets, but
|
||||
+ * S4U2Self should issue a forwardable ticket if the requesting service
|
||||
+ * has no ok-to-auth-as-delegate bit but also no constrained delegation
|
||||
+ * privileges for traditional S4U2Proxy. Implement these rules,
|
||||
+ * extending the check_allowed_to_delegate() DAL method so that the KDC
|
||||
+ * can ask if a principal has any delegation privileges.
|
||||
+ *
|
||||
+ * If target service principal is NULL, and the impersonating service has
|
||||
+ * at least one GCD rule, then succeed.
|
||||
+ */
|
||||
+ if (!proxy) {
|
||||
+ bool has_gcd_rules;
|
||||
+
|
||||
+ kerr = ipadb_has_acl(kcontext, ldap_gcd_acl, &has_gcd_rules);
|
||||
+ if (!kerr)
|
||||
+ kerr = has_gcd_rules ? 0 : KRB5KDC_ERR_BADOPTION;
|
||||
+ } else if (client) {
|
||||
+#else
|
||||
+ if (client && proxy) {
|
||||
+#endif
|
||||
+ kerr = ipadb_match_acl(kcontext, ldap_gcd_acl, client, proxy);
|
||||
+ } else {
|
||||
+ /* client and/or proxy is missing */
|
||||
+ kerr = KRB5KDC_ERR_BADOPTION;
|
||||
}
|
||||
+ if (kerr)
|
||||
+ goto done;
|
||||
|
||||
done:
|
||||
if (kerr) {
|
||||
-#if KRB5_KDB_DAL_MAJOR_VERSION < 9
|
||||
- kerr = KRB5KDC_ERR_POLICY;
|
||||
-#else
|
||||
+#if KRB5_KDB_DAL_MAJOR_VERSION >= 9
|
||||
kerr = KRB5KDC_ERR_BADOPTION;
|
||||
+#else
|
||||
+ kerr = KRB5KDC_ERR_POLICY;
|
||||
#endif
|
||||
}
|
||||
ipadb_free_principal(kcontext, proxy_entry);
|
||||
krb5_free_unparsed_name(kcontext, srv_principal);
|
||||
- ldap_msgfree(res);
|
||||
+ ldap_msgfree(ldap_gcd_acl);
|
||||
return kerr;
|
||||
}
|
||||
--
|
||||
2.44.0
|
||||
|
@ -1,615 +0,0 @@
|
||||
From 542e12325afc2f64298f90296760235bfdcef04a Mon Sep 17 00:00:00 2001
|
||||
From: Julien Rische <jrische@redhat.com>
|
||||
Date: Mon, 25 Mar 2024 18:25:52 +0200
|
||||
Subject: [PATCH] kdb: apply combinatorial logic for ticket flags
|
||||
|
||||
The initial design for ticket flags was implementing this logic:
|
||||
* If a ticket policy is defined for the principal entry, use flags from
|
||||
this policy if they are set. Otherwise, use default ticket flags.
|
||||
* If no ticket policy is defined for the principal entry, but there is a
|
||||
global one, use flags from the global ticket policy if they are set.
|
||||
Otherwise, use default ticket flags.
|
||||
* If no policy (principal nor global) is defined, use default ticket
|
||||
flags.
|
||||
|
||||
However, this logic was broken by a1165ffb which introduced creation of
|
||||
a principal-level ticket policy in case the ticket flag set is modified.
|
||||
This was typically the case for the -allow_tix flag, which was set
|
||||
virtually by the KDB driver when a user was locked until they initialize
|
||||
their password on first kinit pre-authentication.
|
||||
|
||||
This was causing multiple issues, which are mitigated by the new
|
||||
approach:
|
||||
|
||||
Now flags from each level are combined together. There flags like
|
||||
+requires_preauth which are set systematically by the KDB diver, as
|
||||
well as -allow_tix which is set based on the value of "nsAccountLock".
|
||||
This commit also adds the implicit -allow_svr ticket flag for user
|
||||
principals to protect users against Kerberoast-type attacks. None of
|
||||
these flags are stored in the LDAP database, they are hard-coded in the
|
||||
KDB driver.
|
||||
|
||||
In addition to these "virtual" ticket flags, flags from both global and
|
||||
principal ticket policies are applied (if these policies exist).
|
||||
|
||||
Principal ticket policies are not supported for hosts and services, but
|
||||
this is only an HTTP API limitation. The "krbTicketPolicyAux" object
|
||||
class is supported for all account types. This is required for ticket
|
||||
flags like +ok_to_auth_as_delegate. Such flags can be set using "ipa
|
||||
host-mod" and "ipa serivce-mod", or using kadmin's "modprinc".
|
||||
|
||||
It is possible to ignore flags from the global ticket policy or default
|
||||
flags like -allow_svr for a user principal by setting the
|
||||
"final_user_tkt_flags" string attribute to "true" in kadmin. In this
|
||||
case, any ticket flag can be configured in the principal ticket policy,
|
||||
except requires_preauth and allow_tix.
|
||||
|
||||
When in IPA setup mode (using the "ipa-setup-override-restrictions" KDB
|
||||
argument), all the system described above is disabled and ticket flags
|
||||
are written in the principal ticket policy as they are provided. This is
|
||||
required to initialize the Kerberos LDAP container during IPA server
|
||||
installation.
|
||||
|
||||
This fixes CVE-2024-3183
|
||||
|
||||
Signed-off-by: Julien Rische <jrische@redhat.com>
|
||||
---
|
||||
daemons/ipa-kdb/ipa_kdb.h | 43 ++++
|
||||
daemons/ipa-kdb/ipa_kdb_principals.c | 353 +++++++++++++++++++++++----
|
||||
util/ipa_krb5.c | 18 ++
|
||||
util/ipa_krb5.h | 4 +
|
||||
4 files changed, 365 insertions(+), 53 deletions(-)
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
|
||||
index 7baf4697f..85cabe142 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb.h
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb.h
|
||||
@@ -94,6 +94,34 @@
|
||||
#define IPA_KRB_AUTHZ_DATA_ATTR "ipaKrbAuthzData"
|
||||
#define IPA_USER_AUTH_TYPE "ipaUserAuthType"
|
||||
|
||||
+/* Virtual managed ticket flags like "-allow_tix", are always controlled by the
|
||||
+ * "nsAccountLock" attribute, such flags should never be set in the database.
|
||||
+ * The following expression combine all of them, and is used to filter them
|
||||
+ * out. */
|
||||
+#define IPA_KDB_TKTFLAGS_VIRTUAL_MANAGED_ALL (KRB5_KDB_DISALLOW_ALL_TIX)
|
||||
+
|
||||
+/* Virtual static ticket flags are hard-coded in the KDB driver. */
|
||||
+/* Virtual static mandatory flags are set systematically and implicitly for all
|
||||
+ * principals. They are filtered out from database ticket flags updates.
|
||||
+ * (However, "KRB5_KDB_REQUIRES_PRE_AUTH" can still be unset by the
|
||||
+ * "KDC:Disable Default Preauth for SPNs" global setting) */
|
||||
+#define IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_MANDATORY (KRB5_KDB_REQUIRES_PRE_AUTH)
|
||||
+/* Virtual static default ticket flags are implicitly set for user and non-user
|
||||
+ * (SPN) principals, and not stored in the database.
|
||||
+ * (Except if the "IPA_KDB_STRATTR_FINAL_TKTFLAGS" string attribute is "true"
|
||||
+ * the principal) */
|
||||
+/* Virtual static default user ticket flags are set for users only. The
|
||||
+ * "-allow_svr" flag is set to protect them from CVE-2024-3183. */
|
||||
+#define IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_DEFAULTS_USER (KRB5_KDB_DISALLOW_SVR)
|
||||
+#define IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_DEFAULTS_SPN (0)
|
||||
+
|
||||
+/* If this string attribute is set to "true", then only the virtual managed and
|
||||
+ * virtual static mandatory ticket flags are applied and filtered out from
|
||||
+ * database read and write operations for the concerned user principal.
|
||||
+ * Configurable principal ticket flags are applied, but not the configurable
|
||||
+ * global ticket policy flags. */
|
||||
+#define IPA_KDB_STRATTR_FINAL_USER_TKTFLAGS "final_user_tkt_flags"
|
||||
+
|
||||
struct ipadb_mspac;
|
||||
struct dom_sid;
|
||||
|
||||
@@ -178,6 +206,21 @@ struct ipadb_e_data {
|
||||
struct dom_sid *sid;
|
||||
};
|
||||
|
||||
+inline static krb5_error_code
|
||||
+ipadb_get_edata(krb5_db_entry *entry, struct ipadb_e_data **ied)
|
||||
+{
|
||||
+ struct ipadb_e_data *in_ied;
|
||||
+
|
||||
+ in_ied = (struct ipadb_e_data *)entry->e_data;
|
||||
+ if (!in_ied || in_ied->magic != IPA_E_DATA_MAGIC)
|
||||
+ return EINVAL;
|
||||
+
|
||||
+ if (ied)
|
||||
+ *ied = in_ied;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
struct ipadb_context *ipadb_get_context(krb5_context kcontext);
|
||||
int ipadb_get_connection(struct ipadb_context *ipactx);
|
||||
|
||||
diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c
|
||||
index 07cc87746..6eb542d4f 100644
|
||||
--- a/daemons/ipa-kdb/ipa_kdb_principals.c
|
||||
+++ b/daemons/ipa-kdb/ipa_kdb_principals.c
|
||||
@@ -706,9 +706,12 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
|
||||
"krbTicketFlags", &result);
|
||||
if (ret == 0) {
|
||||
entry->attributes = result;
|
||||
- } else {
|
||||
- *polmask |= TKTFLAGS_BIT;
|
||||
}
|
||||
+ /* Since principal, global policy, and virtual ticket flags are combined,
|
||||
+ * they must always be resolved, except if we are in IPA setup mode (because
|
||||
+ * ticket policies and virtual ticket flags are irrelevant in this case). */
|
||||
+ if (!ipactx->override_restrictions)
|
||||
+ *polmask |= TKTFLAGS_BIT;
|
||||
|
||||
ret = ipadb_ldap_attr_to_int(lcontext, lentry,
|
||||
"krbMaxTicketLife", &result);
|
||||
@@ -912,7 +915,12 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
|
||||
goto done;
|
||||
}
|
||||
if (ret == 0) {
|
||||
- ied->ipa_user = true;
|
||||
+ if (1 == krb5_princ_size(kcontext, entry->princ)) {
|
||||
+ /* A principal must be a POSIX account AND have only one element to
|
||||
+ * be considered a user (this is to filter out CIFS principals). */
|
||||
+ ied->ipa_user = true;
|
||||
+ }
|
||||
+
|
||||
ret = ipadb_ldap_attr_to_str(lcontext, lentry,
|
||||
"uid", &uidstring);
|
||||
if (ret != 0 && ret != ENOENT) {
|
||||
@@ -1251,23 +1259,150 @@ done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static krb5_flags maybe_require_preauth(struct ipadb_context *ipactx,
|
||||
- krb5_db_entry *entry)
|
||||
+static krb5_error_code
|
||||
+are_final_tktflags(struct ipadb_context *ipactx, krb5_db_entry *entry,
|
||||
+ bool *final_tktflags)
|
||||
{
|
||||
- const struct ipadb_global_config *config;
|
||||
+ krb5_error_code kerr;
|
||||
struct ipadb_e_data *ied;
|
||||
+ char *str = NULL;
|
||||
+ bool in_final_tktflags = false;
|
||||
|
||||
- config = ipadb_get_global_config(ipactx);
|
||||
- if (config && config->disable_preauth_for_spns) {
|
||||
- ied = (struct ipadb_e_data *)entry->e_data;
|
||||
- if (ied && ied->ipa_user != true) {
|
||||
- /* not a user, assume SPN */
|
||||
- return 0;
|
||||
- }
|
||||
+ kerr = ipadb_get_edata(entry, &ied);
|
||||
+ if (kerr)
|
||||
+ goto end;
|
||||
+
|
||||
+ if (!ied->ipa_user) {
|
||||
+ kerr = 0;
|
||||
+ goto end;
|
||||
}
|
||||
|
||||
- /* By default require preauth for all principals */
|
||||
- return KRB5_KDB_REQUIRES_PRE_AUTH;
|
||||
+ kerr = krb5_dbe_get_string(ipactx->kcontext, entry,
|
||||
+ IPA_KDB_STRATTR_FINAL_USER_TKTFLAGS, &str);
|
||||
+ if (kerr)
|
||||
+ goto end;
|
||||
+
|
||||
+ in_final_tktflags = str && ipa_krb5_parse_bool(str);
|
||||
+
|
||||
+end:
|
||||
+ if (final_tktflags)
|
||||
+ *final_tktflags = in_final_tktflags;
|
||||
+
|
||||
+ krb5_dbe_free_string(ipactx->kcontext, str);
|
||||
+ return kerr;
|
||||
+}
|
||||
+
|
||||
+static krb5_error_code
|
||||
+add_virtual_static_tktflags(struct ipadb_context *ipactx, krb5_db_entry *entry,
|
||||
+ krb5_flags *tktflags)
|
||||
+{
|
||||
+ krb5_error_code kerr;
|
||||
+ krb5_flags vsflg;
|
||||
+ bool final_tktflags;
|
||||
+ const struct ipadb_global_config *gcfg;
|
||||
+ struct ipadb_e_data *ied;
|
||||
+
|
||||
+ vsflg = IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_MANDATORY;
|
||||
+
|
||||
+ kerr = ipadb_get_edata(entry, &ied);
|
||||
+ if (kerr)
|
||||
+ goto end;
|
||||
+
|
||||
+ kerr = are_final_tktflags(ipactx, entry, &final_tktflags);
|
||||
+ if (kerr)
|
||||
+ goto end;
|
||||
+
|
||||
+ /* In practice, principal ticket flags cannot be final for SPNs. */
|
||||
+ if (!final_tktflags)
|
||||
+ vsflg |= ied->ipa_user ? IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_DEFAULTS_USER
|
||||
+ : IPA_KDB_TKTFLAGS_VIRTUAL_STATIC_DEFAULTS_SPN;
|
||||
+
|
||||
+ if (!ied->ipa_user) {
|
||||
+ gcfg = ipadb_get_global_config(ipactx);
|
||||
+ if (gcfg && gcfg->disable_preauth_for_spns)
|
||||
+ vsflg &= ~KRB5_KDB_REQUIRES_PRE_AUTH;
|
||||
+ }
|
||||
+
|
||||
+ if (tktflags)
|
||||
+ *tktflags |= vsflg;
|
||||
+
|
||||
+end:
|
||||
+ return kerr;
|
||||
+}
|
||||
+
|
||||
+static krb5_error_code
|
||||
+get_virtual_static_tktflags_mask(struct ipadb_context *ipactx,
|
||||
+ krb5_db_entry *entry, krb5_flags *mask)
|
||||
+{
|
||||
+ krb5_error_code kerr;
|
||||
+ krb5_flags flags = IPA_KDB_TKTFLAGS_VIRTUAL_MANAGED_ALL;
|
||||
+
|
||||
+ kerr = add_virtual_static_tktflags(ipactx, entry, &flags);
|
||||
+ if (kerr)
|
||||
+ goto end;
|
||||
+
|
||||
+ if (mask)
|
||||
+ *mask = ~flags;
|
||||
+
|
||||
+ kerr = 0;
|
||||
+
|
||||
+end:
|
||||
+ return kerr;
|
||||
+}
|
||||
+
|
||||
+/* Add ticket flags from the global ticket policy if it exists, otherwise
|
||||
+ * succeed. If the global ticket policy is set, the "exists" parameter is set to
|
||||
+ * true. */
|
||||
+static krb5_error_code
|
||||
+add_global_ticket_policy_flags(struct ipadb_context *ipactx,
|
||||
+ bool *gtpol_exists, krb5_flags *tktflags)
|
||||
+{
|
||||
+ krb5_error_code kerr;
|
||||
+ char *policy_dn;
|
||||
+ char *tktflags_attr[] = { "krbticketflags", NULL };
|
||||
+ LDAPMessage *res = NULL, *first;
|
||||
+ int ec, ldap_tktflags;
|
||||
+ bool in_gtpol_exists = false;
|
||||
+
|
||||
+ ec = asprintf(&policy_dn, "cn=%s,cn=kerberos,%s", ipactx->realm,
|
||||
+ ipactx->base);
|
||||
+ if (-1 == ec) {
|
||||
+ kerr = ENOMEM;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ kerr = ipadb_simple_search(ipactx, policy_dn, LDAP_SCOPE_BASE,
|
||||
+ "(objectclass=krbticketpolicyaux)",
|
||||
+ tktflags_attr, &res);
|
||||
+ if (kerr) {
|
||||
+ if (KRB5_KDB_NOENTRY == kerr)
|
||||
+ kerr = 0;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ first = ldap_first_entry(ipactx->lcontext, res);
|
||||
+ if (!first) {
|
||||
+ kerr = 0;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ in_gtpol_exists = true;
|
||||
+
|
||||
+ ec = ipadb_ldap_attr_to_int(ipactx->lcontext, first, "krbticketflags",
|
||||
+ &ldap_tktflags);
|
||||
+ if (0 == ec && tktflags) {
|
||||
+ *tktflags |= (krb5_flags)ldap_tktflags;
|
||||
+ }
|
||||
+
|
||||
+ kerr = 0;
|
||||
+
|
||||
+end:
|
||||
+ if (gtpol_exists)
|
||||
+ *gtpol_exists = in_gtpol_exists;
|
||||
+
|
||||
+ ldap_msgfree(res);
|
||||
+ free(policy_dn);
|
||||
+ return kerr;
|
||||
}
|
||||
|
||||
static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
|
||||
@@ -1280,6 +1415,7 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
|
||||
char *policy_dn = NULL;
|
||||
LDAPMessage *res = NULL;
|
||||
LDAPMessage *first;
|
||||
+ bool final_tktflags, has_local_tktpolicy = true;
|
||||
int result;
|
||||
int ret;
|
||||
|
||||
@@ -1288,12 +1424,18 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
|
||||
return KRB5_KDB_DBNOTINITED;
|
||||
}
|
||||
|
||||
+ kerr = are_final_tktflags(ipactx, entry, &final_tktflags);
|
||||
+ if (kerr)
|
||||
+ goto done;
|
||||
+
|
||||
ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
|
||||
"krbticketpolicyreference", &policy_dn);
|
||||
switch (ret) {
|
||||
case 0:
|
||||
break;
|
||||
case ENOENT:
|
||||
+ /* If no principal ticket policy, fallback to the global one. */
|
||||
+ has_local_tktpolicy = false;
|
||||
ret = asprintf(&policy_dn, "cn=%s,cn=kerberos,%s",
|
||||
ipactx->realm, ipactx->base);
|
||||
if (ret == -1) {
|
||||
@@ -1337,12 +1479,13 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
|
||||
}
|
||||
}
|
||||
if (polmask & TKTFLAGS_BIT) {
|
||||
- ret = ipadb_ldap_attr_to_int(ipactx->lcontext, first,
|
||||
- "krbticketflags", &result);
|
||||
- if (ret == 0) {
|
||||
- entry->attributes |= result;
|
||||
- } else {
|
||||
- entry->attributes |= maybe_require_preauth(ipactx, entry);
|
||||
+ /* If global ticket policy is being applied, set flags only if
|
||||
+ * user principal ticket flags are not final. */
|
||||
+ if (has_local_tktpolicy || !final_tktflags) {
|
||||
+ ret = ipadb_ldap_attr_to_int(ipactx->lcontext, first,
|
||||
+ "krbticketflags", &result);
|
||||
+ if (ret == 0)
|
||||
+ entry->attributes |= result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1366,13 +1509,27 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
|
||||
if (polmask & MAXRENEWABLEAGE_BIT) {
|
||||
entry->max_renewable_life = 604800;
|
||||
}
|
||||
- if (polmask & TKTFLAGS_BIT) {
|
||||
- entry->attributes |= maybe_require_preauth(ipactx, entry);
|
||||
- }
|
||||
|
||||
kerr = 0;
|
||||
}
|
||||
|
||||
+ if (polmask & TKTFLAGS_BIT) {
|
||||
+ /* If the principal ticket flags were applied, then flags from the
|
||||
+ * global ticket policy has to be applied atop of them if user principal
|
||||
+ * ticket flags are not final. */
|
||||
+ if (has_local_tktpolicy && !final_tktflags) {
|
||||
+ kerr = add_global_ticket_policy_flags(ipactx, NULL,
|
||||
+ &entry->attributes);
|
||||
+ if (kerr)
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
+ /* Virtual static ticket flags are set regardless of database content */
|
||||
+ kerr = add_virtual_static_tktflags(ipactx, entry, &entry->attributes);
|
||||
+ if (kerr)
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
done:
|
||||
ldap_msgfree(res);
|
||||
free(policy_dn);
|
||||
@@ -1864,6 +2021,36 @@ static void ipadb_mods_free_tip(struct ipadb_mods *imods)
|
||||
imods->tip--;
|
||||
}
|
||||
|
||||
+/* Use LDAP REPLACE operation to remove an attribute.
|
||||
+ * Contrary to the DELETE operation, it will not fail if the attribute does not
|
||||
+ * exist. */
|
||||
+static krb5_error_code
|
||||
+ipadb_ldap_replace_remove(struct ipadb_mods *imods, char *attribute)
|
||||
+{
|
||||
+ krb5_error_code kerr;
|
||||
+ LDAPMod *m = NULL;
|
||||
+
|
||||
+ kerr = ipadb_mods_new(imods, &m);
|
||||
+ if (kerr)
|
||||
+ return kerr;
|
||||
+
|
||||
+ m->mod_op = LDAP_MOD_REPLACE;
|
||||
+ m->mod_type = strdup(attribute);
|
||||
+ if (!m->mod_type) {
|
||||
+ kerr = ENOMEM;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ m->mod_values = NULL;
|
||||
+
|
||||
+ kerr = 0;
|
||||
+
|
||||
+end:
|
||||
+ if (kerr)
|
||||
+ ipadb_mods_free_tip(imods);
|
||||
+ return kerr;
|
||||
+}
|
||||
+
|
||||
static krb5_error_code ipadb_get_ldap_mod_str(struct ipadb_mods *imods,
|
||||
char *attribute, char *value,
|
||||
int mod_op)
|
||||
@@ -2275,6 +2462,93 @@ static krb5_error_code ipadb_get_ldap_mod_auth_ind(krb5_context kcontext,
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static krb5_error_code
|
||||
+update_tktflags(krb5_context kcontext, struct ipadb_mods *imods,
|
||||
+ krb5_db_entry *entry, int mod_op)
|
||||
+{
|
||||
+ krb5_error_code kerr;
|
||||
+ struct ipadb_context *ipactx;
|
||||
+ struct ipadb_e_data *ied;
|
||||
+ bool final_tktflags;
|
||||
+ krb5_flags tktflags_mask;
|
||||
+ int tktflags;
|
||||
+
|
||||
+ ipactx = ipadb_get_context(kcontext);
|
||||
+ if (!ipactx) {
|
||||
+ kerr = KRB5_KDB_DBNOTINITED;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ if (ipactx->override_restrictions) {
|
||||
+ /* In IPA setup mode, IPA edata might not be available. In this mode,
|
||||
+ * ticket flags are written as they are provided. */
|
||||
+ tktflags = (int)entry->attributes;
|
||||
+ } else {
|
||||
+ kerr = ipadb_get_edata(entry, &ied);
|
||||
+ if (kerr)
|
||||
+ goto end;
|
||||
+
|
||||
+ kerr = get_virtual_static_tktflags_mask(ipactx, entry, &tktflags_mask);
|
||||
+ if (kerr)
|
||||
+ goto end;
|
||||
+
|
||||
+ kerr = are_final_tktflags(ipactx, entry, &final_tktflags);
|
||||
+ if (kerr)
|
||||
+ goto end;
|
||||
+
|
||||
+ /* Flags from the global ticket policy are filtered out only if the user
|
||||
+ * principal flags are not final. */
|
||||
+ if (!final_tktflags) {
|
||||
+ krb5_flags gbl_tktflags = 0;
|
||||
+
|
||||
+ kerr = add_global_ticket_policy_flags(ipactx, NULL, &gbl_tktflags);
|
||||
+ if (kerr)
|
||||
+ goto end;
|
||||
+
|
||||
+ tktflags_mask &= ~gbl_tktflags;
|
||||
+ }
|
||||
+
|
||||
+ tktflags = (int)(entry->attributes & tktflags_mask);
|
||||
+
|
||||
+ if (LDAP_MOD_REPLACE == mod_op && ied && !ied->has_tktpolaux) {
|
||||
+ if (0 == tktflags) {
|
||||
+ /* No point initializing principal ticket policy if there are no
|
||||
+ * flags left after filtering out virtual and global ticket
|
||||
+ * policy ones. */
|
||||
+ kerr = 0;
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ /* if the object does not have the krbTicketPolicyAux class
|
||||
+ * we need to add it or this will fail, only for modifications.
|
||||
+ * We always add this objectclass by default when doing an add
|
||||
+ * from scratch. */
|
||||
+ kerr = ipadb_get_ldap_mod_str(imods, "objectclass",
|
||||
+ "krbTicketPolicyAux", LDAP_MOD_ADD);
|
||||
+ if (kerr)
|
||||
+ goto end;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (tktflags != 0) {
|
||||
+ kerr = ipadb_get_ldap_mod_int(imods, "krbTicketFlags", tktflags,
|
||||
+ mod_op);
|
||||
+ if (kerr)
|
||||
+ goto end;
|
||||
+ } else if (LDAP_MOD_REPLACE == mod_op) {
|
||||
+ /* If the principal is not being created, and there are no custom ticket
|
||||
+ * flags to be set, remove the "krbTicketFlags" attribute. */
|
||||
+ kerr = ipadb_ldap_replace_remove(imods, "krbTicketFlags");
|
||||
+ if (kerr)
|
||||
+ goto end;
|
||||
+ }
|
||||
+
|
||||
+ kerr = 0;
|
||||
+
|
||||
+end:
|
||||
+ return kerr;
|
||||
+}
|
||||
+
|
||||
static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext,
|
||||
struct ipadb_mods *imods,
|
||||
krb5_db_entry *entry,
|
||||
@@ -2350,36 +2624,9 @@ static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext,
|
||||
|
||||
/* KADM5_ATTRIBUTES */
|
||||
if (entry->mask & KMASK_ATTRIBUTES) {
|
||||
- /* if the object does not have the krbTicketPolicyAux class
|
||||
- * we need to add it or this will fail, only for modifications.
|
||||
- * We always add this objectclass by default when doing an add
|
||||
- * from scratch. */
|
||||
- if ((mod_op == LDAP_MOD_REPLACE) && entry->e_data) {
|
||||
- struct ipadb_e_data *ied;
|
||||
-
|
||||
- ied = (struct ipadb_e_data *)entry->e_data;
|
||||
- if (ied->magic != IPA_E_DATA_MAGIC) {
|
||||
- kerr = EINVAL;
|
||||
- goto done;
|
||||
- }
|
||||
-
|
||||
- if (!ied->has_tktpolaux) {
|
||||
- kerr = ipadb_get_ldap_mod_str(imods, "objectclass",
|
||||
- "krbTicketPolicyAux",
|
||||
- LDAP_MOD_ADD);
|
||||
- if (kerr) {
|
||||
- goto done;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- kerr = ipadb_get_ldap_mod_int(imods,
|
||||
- "krbTicketFlags",
|
||||
- (int)entry->attributes,
|
||||
- mod_op);
|
||||
- if (kerr) {
|
||||
+ kerr = update_tktflags(kcontext, imods, entry, mod_op);
|
||||
+ if (kerr)
|
||||
goto done;
|
||||
- }
|
||||
}
|
||||
|
||||
/* KADM5_MAX_LIFE */
|
||||
diff --git a/util/ipa_krb5.c b/util/ipa_krb5.c
|
||||
index 1ba6d25ee..2e663c506 100644
|
||||
--- a/util/ipa_krb5.c
|
||||
+++ b/util/ipa_krb5.c
|
||||
@@ -38,6 +38,12 @@ const char *ipapwd_password_max_len_errmsg = \
|
||||
TOSTR(IPAPWD_PASSWORD_MAX_LEN) \
|
||||
" chars)!";
|
||||
|
||||
+/* Case-insensitive string values to by parsed as boolean true */
|
||||
+static const char *const conf_yes[] = {
|
||||
+ "y", "yes", "true", "t", "1", "on",
|
||||
+ NULL,
|
||||
+};
|
||||
+
|
||||
/* Salt types */
|
||||
#define KRB5P_SALT_SIZE 16
|
||||
|
||||
@@ -1237,3 +1243,15 @@ done:
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
+
|
||||
+bool ipa_krb5_parse_bool(const char *str)
|
||||
+{
|
||||
+ const char *const *p;
|
||||
+
|
||||
+ for (p = conf_yes; *p; p++) {
|
||||
+ if (!strcasecmp(*p, str))
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
diff --git a/util/ipa_krb5.h b/util/ipa_krb5.h
|
||||
index 7d2ebae98..d0280940a 100644
|
||||
--- a/util/ipa_krb5.h
|
||||
+++ b/util/ipa_krb5.h
|
||||
@@ -174,3 +174,7 @@ static inline bool
|
||||
krb5_ts_after(krb5_timestamp a, krb5_timestamp b) {
|
||||
return (uint32_t)a > (uint32_t)b;
|
||||
}
|
||||
+
|
||||
+/* Implement boolean string parsing function from MIT krb5:
|
||||
+ * src/lib/krb5/krb/libdef_parse.c:_krb5_conf_boolean() */
|
||||
+bool ipa_krb5_parse_bool(const char *str);
|
||||
--
|
||||
2.45.1
|
||||
|
@ -0,0 +1,148 @@
|
||||
From c71e12e902b3912c31245d46ad6f2c2ddee01126 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Tue, 1 Oct 2024 11:28:28 +0300
|
||||
Subject: [PATCH] selinux: allow Cockpit to use HTTP keytab on IPA servers
|
||||
|
||||
Cockpit can use GSSAPI authentication and has pretty good definition of
|
||||
how to enable it: https://cockpit-project.org/guide/latest/sso.html.
|
||||
These instructions work on IPA clients but they cannot be used on IPA
|
||||
servers because IPA framework already owns HTTP/.. Kerberos service and
|
||||
its keytab.
|
||||
|
||||
Luckily, there are two changes that need to be done to enable Cockpit
|
||||
single sign-on with GSSAPI on IPA servers:
|
||||
|
||||
- create a symlink /etc/cockpit/krb5.keytab to
|
||||
/var/lib/ipa/gssproxy/http.keytab
|
||||
|
||||
- add SELinux policy to allow cockpit_session_t to operate on
|
||||
/var/lib/ipa/gssproxy/http.keytab file
|
||||
|
||||
For existing installation an upgrade process would restore SELinux
|
||||
context of the http.keytab file to the new value.
|
||||
|
||||
Note that Cockpit documentation above also talks about Kerberos service
|
||||
modifications to enable delegation. These modifications should not be
|
||||
done for IPA servers' HTTP services, as these services are already
|
||||
enabled to handle delegation.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9675
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipaserver/install/server/upgrade.py | 1 +
|
||||
selinux/ipa.fc | 2 ++
|
||||
selinux/ipa.if | 24 ++++++++++++++++++++++++
|
||||
selinux/ipa.te | 19 +++++++++++++++++++
|
||||
4 files changed, 46 insertions(+)
|
||||
|
||||
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
|
||||
index 31d4f8398cfb0251cc59ada909eb55635b83e960..d5c466ee2f905eafd15663fef46d052ade30d742 100644
|
||||
--- a/ipaserver/install/server/upgrade.py
|
||||
+++ b/ipaserver/install/server/upgrade.py
|
||||
@@ -1124,6 +1124,7 @@ def update_http_keytab(http):
|
||||
paths.OLD_IPA_KEYTAB, e
|
||||
)
|
||||
http.keytab_user.chown(http.keytab)
|
||||
+ tasks.restore_context(http.keytab)
|
||||
|
||||
|
||||
def ds_enable_sidgen_extdom_plugins(ds):
|
||||
diff --git a/selinux/ipa.fc b/selinux/ipa.fc
|
||||
index 47bd19ba77418cad1f0904dc4a9a35ce9d6ff9d2..15e8e41aa50228ff560e338044240b46bc24cc40 100644
|
||||
--- a/selinux/ipa.fc
|
||||
+++ b/selinux/ipa.fc
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
/var/lib/ipa(/.*)? gen_context(system_u:object_r:ipa_var_lib_t,s0)
|
||||
|
||||
+/var/lib/ipa/gssproxy/http.keytab -- gen_context(system_u:object_r:ipa_http_keytab_t,s0)
|
||||
+
|
||||
/var/log/ipa(/.*)? gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
|
||||
/var/log/ipabackup.log -- gen_context(system_u:object_r:ipa_log_t,s0)
|
||||
diff --git a/selinux/ipa.if b/selinux/ipa.if
|
||||
index 8c47e7963af92b1ddcd59d92aa45d6b8e9c0c6cc..8f3147e10bd294665dd41e1c1f99c993d9699d20 100644
|
||||
--- a/selinux/ipa.if
|
||||
+++ b/selinux/ipa.if
|
||||
@@ -155,6 +155,7 @@ interface(`ipa_manage_log',`
|
||||
########################################
|
||||
## <summary>
|
||||
## Allow domain to manage ipa lib files/dirs.
|
||||
+## This includes reading ipa_http_keytab_t files.
|
||||
## </summary>
|
||||
## <param name="domain">
|
||||
## <summary>
|
||||
@@ -164,10 +165,33 @@ interface(`ipa_manage_log',`
|
||||
#
|
||||
interface(`ipa_read_lib',`
|
||||
gen_require(`
|
||||
+ type ipa_http_keytab_t;
|
||||
type ipa_var_lib_t;
|
||||
')
|
||||
|
||||
read_files_pattern($1, ipa_var_lib_t, ipa_var_lib_t)
|
||||
+ read_files_pattern($1, ipa_http_keytab_t, ipa_http_keytab_t)
|
||||
+ list_dirs_pattern($1, ipa_var_lib_t, ipa_var_lib_t)
|
||||
+')
|
||||
+
|
||||
+########################################
|
||||
+## <summary>
|
||||
+## Allow domain to manage ipa HTTP keytab file.
|
||||
+## This includes reading ipa_var_lib_t directories.
|
||||
+## </summary>
|
||||
+## <param name="domain">
|
||||
+## <summary>
|
||||
+## Domain allowed access.
|
||||
+## </summary>
|
||||
+## </param>
|
||||
+#
|
||||
+interface(`ipa_read_http_keytab',`
|
||||
+ gen_require(`
|
||||
+ type ipa_http_keytab_t;
|
||||
+ type ipa_var_lib_t;
|
||||
+ ')
|
||||
+
|
||||
+ read_files_pattern($1, ipa_http_keytab_t, ipa_http_keytab_t)
|
||||
list_dirs_pattern($1, ipa_var_lib_t, ipa_var_lib_t)
|
||||
')
|
||||
|
||||
diff --git a/selinux/ipa.te b/selinux/ipa.te
|
||||
index 2546a9bd9468200185c484974a9e71f16f89de71..e4ce66687a48b27e85591cdd8352f7cac94d3151 100644
|
||||
--- a/selinux/ipa.te
|
||||
+++ b/selinux/ipa.te
|
||||
@@ -43,6 +43,9 @@ logging_log_file(ipa_log_t)
|
||||
type ipa_var_lib_t;
|
||||
files_type(ipa_var_lib_t)
|
||||
|
||||
+type ipa_http_keytab_t;
|
||||
+files_type(ipa_http_keytab_t)
|
||||
+
|
||||
type ipa_var_run_t;
|
||||
files_pid_file(ipa_var_run_t)
|
||||
|
||||
@@ -516,3 +519,19 @@ optional_policy(`
|
||||
')
|
||||
allow certmonger_t pki_tomcat_etc_rw_t:file { getattr ioctl open read };
|
||||
')
|
||||
+
|
||||
+# gssproxy needs to read http keytab
|
||||
+optional_policy(`
|
||||
+ gen_require(`
|
||||
+ type gssproxy_t;
|
||||
+ ')
|
||||
+ ipa_read_http_keytab(gssproxy_t)
|
||||
+')
|
||||
+
|
||||
+# Allow Cockpit to use HTTP keytab on IPA servers for GSSAPI authentication
|
||||
+optional_policy(`
|
||||
+ gen_require(`
|
||||
+ type cockpit_session_t;
|
||||
+ ')
|
||||
+ ipa_read_http_keytab(cockpit_session_t)
|
||||
+')
|
||||
--
|
||||
2.47.0
|
||||
|
@ -1,127 +0,0 @@
|
||||
diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py
|
||||
index 6f5e349..febc22f 100644
|
||||
--- a/ipaserver/plugins/user.py
|
||||
+++ b/ipaserver/plugins/user.py
|
||||
@@ -144,8 +144,7 @@ PROTECTED_USERS = ('admin',)
|
||||
def check_protected_member(user, protected_group_name=u'admins'):
|
||||
'''
|
||||
Ensure admin and the last enabled member of a protected group cannot
|
||||
- be deleted or disabled by raising ProtectedEntryError or
|
||||
- LastMemberError as appropriate.
|
||||
+ be deleted.
|
||||
'''
|
||||
|
||||
if user in PROTECTED_USERS:
|
||||
@@ -155,6 +154,12 @@ def check_protected_member(user, protected_group_name=u'admins'):
|
||||
reason=_("privileged user"),
|
||||
)
|
||||
|
||||
+
|
||||
+def check_last_member(user, protected_group_name=u'admins'):
|
||||
+ '''
|
||||
+ Ensure the last enabled member of a protected group cannot
|
||||
+ be disabled.
|
||||
+ '''
|
||||
# Get all users in the protected group
|
||||
result = api.Command.user_find(in_group=protected_group_name)
|
||||
|
||||
@@ -796,6 +801,7 @@ class user_del(baseuser_del):
|
||||
# If the target entry is a Delete entry, skip the orphaning/removal
|
||||
# of OTP tokens.
|
||||
check_protected_member(keys[-1])
|
||||
+ check_last_member(keys[-1])
|
||||
|
||||
preserve = options.get('preserve', False)
|
||||
|
||||
@@ -1128,7 +1134,7 @@ class user_disable(LDAPQuery):
|
||||
def execute(self, *keys, **options):
|
||||
ldap = self.obj.backend
|
||||
|
||||
- check_protected_member(keys[-1])
|
||||
+ check_last_member(keys[-1])
|
||||
|
||||
dn, _oc = self.obj.get_either_dn(*keys, **options)
|
||||
ldap.deactivate_entry(dn)
|
||||
diff --git a/ipatests/test_integration/test_commands.py b/ipatests/test_integration/test_commands.py
|
||||
index c0cb4d0..c2a55b8 100644
|
||||
--- a/ipatests/test_integration/test_commands.py
|
||||
+++ b/ipatests/test_integration/test_commands.py
|
||||
@@ -1530,6 +1530,30 @@ class TestIPACommand(IntegrationTest):
|
||||
|
||||
assert 'Discovered server %s' % self.master.hostname in result
|
||||
|
||||
+ def test_delete_last_enabled_admin(self):
|
||||
+ """
|
||||
+ The admin user may be disabled. Don't allow all other
|
||||
+ members of admins to be removed if the admin user is
|
||||
+ disabled which would leave the install with no
|
||||
+ usable admins users
|
||||
+ """
|
||||
+ user = 'adminuser2'
|
||||
+ passwd = 'Secret123'
|
||||
+ tasks.create_active_user(self.master, user, passwd)
|
||||
+ tasks.kinit_admin(self.master)
|
||||
+ self.master.run_command(['ipa', 'group-add-member', 'admins',
|
||||
+ '--users', user])
|
||||
+ tasks.kinit_user(self.master, user, passwd)
|
||||
+ self.master.run_command(['ipa', 'user-disable', 'admin'])
|
||||
+ result = self.master.run_command(
|
||||
+ ['ipa', 'user-del', user],
|
||||
+ raiseonerr=False
|
||||
+ )
|
||||
+ self.master.run_command(['ipa', 'user-enable', 'admin'])
|
||||
+ tasks.kdestroy_all(self.master)
|
||||
+ assert result.returncode == 1
|
||||
+ assert 'cannot be deleted or disabled' in result.stderr_text
|
||||
+
|
||||
|
||||
class TestIPACommandWithoutReplica(IntegrationTest):
|
||||
"""
|
||||
diff --git a/ipatests/test_xmlrpc/test_user_plugin.py b/ipatests/test_xmlrpc/test_user_plugin.py
|
||||
index 3c58845..68c6c48 100644
|
||||
--- a/ipatests/test_xmlrpc/test_user_plugin.py
|
||||
+++ b/ipatests/test_xmlrpc/test_user_plugin.py
|
||||
@@ -1045,8 +1045,8 @@ class TestAdmins(XMLRPC_test):
|
||||
tracker = Tracker()
|
||||
command = tracker.make_command('user_disable', admin1)
|
||||
|
||||
- with raises_exact(errors.ProtectedEntryError(label=u'user',
|
||||
- key=admin1, reason='privileged user')):
|
||||
+ with raises_exact(errors.LastMemberError(label=u'group',
|
||||
+ key=admin1, container=admin_group)):
|
||||
command()
|
||||
|
||||
def test_create_admin2(self, admin2):
|
||||
@@ -1064,8 +1064,8 @@ class TestAdmins(XMLRPC_test):
|
||||
admin2.disable()
|
||||
tracker = Tracker()
|
||||
|
||||
- with raises_exact(errors.ProtectedEntryError(label=u'user',
|
||||
- key=admin1, reason='privileged user')):
|
||||
+ with raises_exact(errors.LastMemberError(label=u'group',
|
||||
+ key=admin1, container=admin_group)):
|
||||
tracker.run_command('user_disable', admin1)
|
||||
admin2.delete()
|
||||
|
||||
diff --git a/ipatests/test_webui/test_user.py b/ipatests/test_webui/test_user.py
|
||||
index a8a92d0..9083e50 100644
|
||||
--- a/ipatests/test_webui/test_user.py
|
||||
+++ b/ipatests/test_webui/test_user.py
|
||||
@@ -50,6 +50,8 @@ 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_DISABLE = ('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'
|
||||
@@ -546,7 +548,7 @@ class test_user(user_tasks):
|
||||
self.select_record('admin')
|
||||
self.facet_button_click('disable')
|
||||
self.dialog_button_click('ok')
|
||||
- self.assert_last_error_dialog(ERR_ADMIN_DEL, details=True)
|
||||
+ self.assert_last_error_dialog(ERR_ADMIN_DISABLE, details=True)
|
||||
self.dialog_button_click('ok')
|
||||
self.assert_record('admin')
|
||||
|
@ -0,0 +1,94 @@
|
||||
From 0dadcbb4ac9f6142b5130f025f64d918d6f208a9 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Tue, 8 Oct 2024 10:25:08 +0300
|
||||
Subject: [PATCH] Minimal test for Cockpit integration on IPA master
|
||||
|
||||
Add a test to share HTTP service keytab on IPA master between IPA and
|
||||
Cockpit. The test configures Cockpit with IPA CA-issued certificate and
|
||||
allows Cockpit to access IPA HTTP service keytab for authentication.
|
||||
|
||||
The test then attempts to authenticate with GSSAPI as admin user. A
|
||||
successful result is when we receive CSRF token from the Cockpit as
|
||||
the result of this authentication. This means we have logged in
|
||||
successfully with Kerberos.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9675
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipatests/test_integration/test_cockpit.py | 61 +++++++++++++++++++++++
|
||||
1 file changed, 61 insertions(+)
|
||||
create mode 100644 ipatests/test_integration/test_cockpit.py
|
||||
|
||||
diff --git a/ipatests/test_integration/test_cockpit.py b/ipatests/test_integration/test_cockpit.py
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..cdc96170a116536c7aa00be78cc4e0225804e21c
|
||||
--- /dev/null
|
||||
+++ b/ipatests/test_integration/test_cockpit.py
|
||||
@@ -0,0 +1,61 @@
|
||||
+#
|
||||
+# Copyright (C) 2024 FreeIPA Contributors see COPYING for license
|
||||
+#
|
||||
+
|
||||
+from __future__ import absolute_import
|
||||
+
|
||||
+import time
|
||||
+from ipatests.pytest_ipa.integration import tasks
|
||||
+from ipatests.test_integration.base import IntegrationTest
|
||||
+from ipaplatform.paths import paths
|
||||
+
|
||||
+
|
||||
+class TestCockpitIntegration(IntegrationTest):
|
||||
+ topology = "line"
|
||||
+ reqcert = '/etc/cockpit/ws-certs.d/99-cockpit.cert'
|
||||
+ reqkey = '/etc/cockpit/ws-certs.d/99-cockpit.key'
|
||||
+ symlink = '/etc/cockpit/krb5.keytab'
|
||||
+
|
||||
+ @classmethod
|
||||
+ def uninstall(cls, mh):
|
||||
+ cls.master.run_command(['ipa-getcert', 'stop-tracking', '-f',
|
||||
+ cls.reqcert], raiseonerr=False)
|
||||
+ cls.master.run_command(['rm', '-f', cls.symlink], raiseonerr=False)
|
||||
+ cls.master.run_command(['systemctl', 'disable', '--now',
|
||||
+ 'cockpit.socket'])
|
||||
+ super(TestCockpitIntegration, cls).uninstall(mh)
|
||||
+
|
||||
+ @classmethod
|
||||
+ def install(cls, mh):
|
||||
+ master = cls.master
|
||||
+
|
||||
+ # Install Cockpit and configure it to use IPA certificate and keytab
|
||||
+ master.run_command(['dnf', 'install', '-y', 'cockpit', 'curl'],
|
||||
+ raiseonerr=False)
|
||||
+
|
||||
+ super(TestCockpitIntegration, cls).install(mh)
|
||||
+
|
||||
+ master.run_command(['ipa-getcert', 'request', '-f', cls.reqcert, '-k',
|
||||
+ cls.reqkey, '-D', cls.master.hostname, '-K',
|
||||
+ 'host/' + cls.master.hostname, '-m', '0640', '-o',
|
||||
+ 'root:cockpit-ws', '-O', 'root:root', '-M',
|
||||
+ '0644'], raiseonerr=False)
|
||||
+
|
||||
+ master.run_command(['ln', '-s', paths.HTTP_KEYTAB, cls.symlink],
|
||||
+ raiseonerr=False)
|
||||
+
|
||||
+ time.sleep(5)
|
||||
+ master.run_command(['systemctl', 'enable', '--now', 'cockpit.socket'])
|
||||
+
|
||||
+ def test_login_with_kerberos(self):
|
||||
+ """
|
||||
+ Login to Cockpit using GSSAPI authentication
|
||||
+ """
|
||||
+ master = self.master
|
||||
+ tasks.kinit_admin(master)
|
||||
+
|
||||
+ cockpit_login = f'https://{master.hostname}:9090/cockpit/login'
|
||||
+ result = master.run_command([paths.BIN_CURL, '-u:', '--negotiate',
|
||||
+ '--cacert', paths.IPA_CA_CRT,
|
||||
+ cockpit_login])
|
||||
+ assert ("csrf-token" in result.stdout_text)
|
||||
--
|
||||
2.47.0
|
||||
|
@ -1,13 +0,0 @@
|
||||
diff --git a/ipaserver/install/ipa_otptoken_import.py b/ipaserver/install/ipa_otptoken_import.py
|
||||
index b3f9347..75e8680 100644
|
||||
--- a/ipaserver/install/ipa_otptoken_import.py
|
||||
+++ b/ipaserver/install/ipa_otptoken_import.py
|
||||
@@ -539,7 +539,7 @@ class OTPTokenImport(admintool.AdminTool):
|
||||
|
||||
# Load the keyfile.
|
||||
keyfile = self.safe_options.keyfile
|
||||
- with open(keyfile) as f:
|
||||
+ with open(keyfile, "rb") as f:
|
||||
self.doc.setKey(f.read())
|
||||
|
||||
def run(self):
|
38
SOURCES/0030-ipaserver-dcerpc-support-Samba-4.21.patch
Normal file
38
SOURCES/0030-ipaserver-dcerpc-support-Samba-4.21.patch
Normal file
@ -0,0 +1,38 @@
|
||||
From c306c613399cdd9a2c716b83ce0d47d320aec2a8 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Tue, 19 Nov 2024 12:57:46 +0200
|
||||
Subject: [PATCH] ipaserver/dcerpc: support Samba 4.21
|
||||
|
||||
Samba 4.21 moved samba.trust_utils module to samba.lsa_utils.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9702
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
---
|
||||
ipaserver/dcerpc.py | 8 ++++++--
|
||||
1 file changed, 6 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
|
||||
index a28c72361276f12a1a02cd126425ac3c62eddd4f..3344ea226e3cba61912e717f9c375612bb4707e0 100644
|
||||
--- a/ipaserver/dcerpc.py
|
||||
+++ b/ipaserver/dcerpc.py
|
||||
@@ -55,9 +55,13 @@ from samba import ntstatus
|
||||
import samba
|
||||
|
||||
try:
|
||||
- from samba.trust_utils import CreateTrustedDomainRelax
|
||||
+ from samba.lsa_utils import CreateTrustedDomainRelax
|
||||
except ImportError:
|
||||
- CreateTrustedDomainRelax = None
|
||||
+ try:
|
||||
+ from samba.trust_utils import CreateTrustedDomainRelax
|
||||
+ except ImportError:
|
||||
+ CreateTrustedDomainRelax = None
|
||||
+
|
||||
try:
|
||||
from samba import arcfour_encrypt
|
||||
except ImportError:
|
||||
--
|
||||
2.47.0
|
||||
|
@ -0,0 +1,66 @@
|
||||
From 184589fac4ff36b5583541f40dff91296c33370a Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Mon, 2 Dec 2024 10:23:29 -0500
|
||||
Subject: [PATCH] Allow looking up constants.Group by gid in addition to name
|
||||
|
||||
This adds flexibility so we can look up groups by both gid and
|
||||
by name in order to have a more consistent API for management.
|
||||
|
||||
Related: https://pagure.io/freeipa/issue/9709
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
|
||||
---
|
||||
ipaplatform/base/constants.py | 5 ++++-
|
||||
ipatests/test_ipaplatform/test_constants.py | 11 +++++++++++
|
||||
2 files changed, 15 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ipaplatform/base/constants.py b/ipaplatform/base/constants.py
|
||||
index 1689efe52466f00fd8b014f720e1d21ebdbf2504..f1ef7efff502573bab82e890bcdf87c0ec52a399 100644
|
||||
--- a/ipaplatform/base/constants.py
|
||||
+++ b/ipaplatform/base/constants.py
|
||||
@@ -86,7 +86,10 @@ class Group(_Entity):
|
||||
try:
|
||||
self._entity = entity = grp.getgrnam(self)
|
||||
except KeyError:
|
||||
- raise ValueError(f"group '{self!s}' not found") from None
|
||||
+ try:
|
||||
+ self._entity = entity = grp.getgrgid(int(self))
|
||||
+ except (TypeError, ValueError):
|
||||
+ raise ValueError(f"group '{self!s}' not found") from None
|
||||
return entity
|
||||
|
||||
@property
|
||||
diff --git a/ipatests/test_ipaplatform/test_constants.py b/ipatests/test_ipaplatform/test_constants.py
|
||||
index b57bfa48e5ccefe2b22cb00aca8436e0edc01a30..9bb12283609f87bcd875a2c55ee1e8b714dd8b3a 100644
|
||||
--- a/ipatests/test_ipaplatform/test_constants.py
|
||||
+++ b/ipatests/test_ipaplatform/test_constants.py
|
||||
@@ -1,6 +1,7 @@
|
||||
#
|
||||
# Copyright (C) 2020 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
+import grp
|
||||
import pytest
|
||||
|
||||
from ipaplatform.base.constants import User, Group
|
||||
@@ -40,6 +41,16 @@ def test_group():
|
||||
assert Group(str(group)) is not group
|
||||
|
||||
|
||||
+def test_numeric_group():
|
||||
+ g = grp.getgrnam('apache')
|
||||
+ group = Group(g.gr_gid)
|
||||
+ assert group.gid == g.gr_gid
|
||||
+ assert type(str(group)) is str
|
||||
+ assert repr(group) == '<Group "%d">' % g.gr_gid
|
||||
+ assert group.gid == g.gr_gid
|
||||
+ assert group.entity.gr_gid == g.gr_gid
|
||||
+
|
||||
+
|
||||
def test_group_invalid():
|
||||
invalid = Group("invalid")
|
||||
with pytest.raises(ValueError) as e:
|
||||
--
|
||||
2.47.1
|
||||
|
@ -1,114 +0,0 @@
|
||||
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
|
||||
index 38693c9..35cec89 100644
|
||||
--- a/ipaserver/install/cainstance.py
|
||||
+++ b/ipaserver/install/cainstance.py
|
||||
@@ -1327,6 +1327,8 @@ class CAInstance(DogtagInstance):
|
||||
generation master:
|
||||
- in CS.cfg ca.crl.MasterCRL.enableCRLCache=true
|
||||
- in CS.cfg ca.crl.MasterCRL.enableCRLUpdates=true
|
||||
+ - in CS.cfg ca.listenToCloneModifications=true
|
||||
+ - in CS.cfg ca.certStatusUpdateInterval != 0
|
||||
- in /etc/httpd/conf.d/ipa-pki-proxy.conf the RewriteRule
|
||||
^/ipa/crl/MasterCRL.bin is disabled (commented or removed)
|
||||
|
||||
@@ -1342,15 +1344,30 @@ class CAInstance(DogtagInstance):
|
||||
updates = directivesetter.get_directive(
|
||||
self.config, 'ca.crl.MasterCRL.enableCRLUpdates', '=')
|
||||
enableCRLUpdates = updates.lower() == 'true'
|
||||
+ listen = directivesetter.get_directive(
|
||||
+ self.config, 'ca.listenToCloneModifications', '=')
|
||||
+ enableToClone = listen.lower() == 'true'
|
||||
+ updateinterval = directivesetter.get_directive(
|
||||
+ self.config, 'ca.certStatusUpdateInterval', '=')
|
||||
|
||||
# If the values are different, the config is inconsistent
|
||||
- if enableCRLCache != enableCRLUpdates:
|
||||
+ if not (enableCRLCache == enableCRLUpdates == enableToClone):
|
||||
raise InconsistentCRLGenConfigException(
|
||||
"Configuration is inconsistent, please check "
|
||||
- "ca.crl.MasterCRL.enableCRLCache and "
|
||||
- "ca.crl.MasterCRL.enableCRLUpdates in {} and "
|
||||
+ "ca.crl.MasterCRL.enableCRLCache, "
|
||||
+ "ca.crl.MasterCRL.enableCRLUpdates and "
|
||||
+ "ca.listenToCloneModifications in {} and "
|
||||
"run ipa-crlgen-manage [enable|disable] to repair".format(
|
||||
self.config))
|
||||
+ # If they are the same then we are the CRL renewal master. Ensure
|
||||
+ # the update task is configured.
|
||||
+ if enableCRLCache and updateinterval == '0':
|
||||
+ raise InconsistentCRLGenConfigException(
|
||||
+ "Configuration is inconsistent, please check "
|
||||
+ "ca.certStatusUpdateInterval in {}. It should "
|
||||
+ "be either not present or not zero. Run "
|
||||
+ "ipa-crlgen-manage [enable|disable] to repair".format(
|
||||
+ self.config))
|
||||
except IOError:
|
||||
raise RuntimeError(
|
||||
"Unable to read {}".format(self.config))
|
||||
@@ -1407,6 +1424,11 @@ class CAInstance(DogtagInstance):
|
||||
str_value = str(setup_crlgen).lower()
|
||||
ds.set('ca.crl.MasterCRL.enableCRLCache', str_value)
|
||||
ds.set('ca.crl.MasterCRL.enableCRLUpdates', str_value)
|
||||
+ ds.set('ca.listenToCloneModifications', str_value)
|
||||
+ if setup_crlgen:
|
||||
+ ds.set('ca.certStatusUpdateInterval', None)
|
||||
+ else:
|
||||
+ ds.set('ca.certStatusUpdateInterval', '0')
|
||||
|
||||
# Start pki-tomcat
|
||||
logger.info("Starting %s", self.service_name)
|
||||
diff --git a/ipatests/test_integration/test_crlgen_manage.py b/ipatests/test_integration/test_crlgen_manage.py
|
||||
index 2a733bd..c6f41eb 100644
|
||||
--- a/ipatests/test_integration/test_crlgen_manage.py
|
||||
+++ b/ipatests/test_integration/test_crlgen_manage.py
|
||||
@@ -61,6 +61,16 @@ def check_crlgen_status(host, rc=0, msg=None, enabled=True, check_crl=False):
|
||||
ext.value.crl_number)
|
||||
assert number_msg in result.stdout_text
|
||||
|
||||
+ try:
|
||||
+ value = get_CS_cfg_value(host, 'ca.certStatusUpdateInterval')
|
||||
+ except IOError:
|
||||
+ return
|
||||
+
|
||||
+ if enabled:
|
||||
+ assert value is None
|
||||
+ else:
|
||||
+ assert value == '0'
|
||||
+
|
||||
|
||||
def check_crlgen_enable(host, rc=0, msg=None, check_crl=False):
|
||||
"""Check ipa-crlgen-manage enable command
|
||||
@@ -125,6 +135,23 @@ def break_crlgen_with_CS_cfg(host):
|
||||
check_crlgen_status(host, rc=1, msg="Configuration is inconsistent")
|
||||
|
||||
|
||||
+def get_CS_cfg_value(host, directive):
|
||||
+ """Retrieve and return the a directive from the CA CS.cfg
|
||||
+
|
||||
+ This returns None if the directives is not found.
|
||||
+ """
|
||||
+ content = host.get_file_contents(paths.CA_CS_CFG_PATH,
|
||||
+ encoding='utf-8')
|
||||
+ value = None
|
||||
+ for line in content.split('\n'):
|
||||
+ l = line.lower()
|
||||
+
|
||||
+ if l.startswith(directive.lower()):
|
||||
+ value = line.split('=', 1)[1]
|
||||
+
|
||||
+ return value
|
||||
+
|
||||
+
|
||||
class TestCRLGenManage(IntegrationTest):
|
||||
"""Tests the ipa-crlgen-manage command.
|
||||
|
||||
@@ -196,6 +223,9 @@ class TestCRLGenManage(IntegrationTest):
|
||||
|
||||
Install a CA clone and enable CRLgen"""
|
||||
tasks.install_ca(self.replicas[0])
|
||||
+ value = get_CS_cfg_value(self.replicas[0],
|
||||
+ 'ca.certStatusUpdateInterval')
|
||||
+ assert value == '0'
|
||||
check_crlgen_enable(
|
||||
self.replicas[0], rc=0,
|
||||
msg="make sure to have only a single CRL generation master",
|
@ -0,0 +1,72 @@
|
||||
From 934d4a291d44a40b5ea006aa1f09afa8e4a985fc Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Mon, 2 Dec 2024 10:27:15 -0500
|
||||
Subject: [PATCH] Pass all pkiuser groups as suplementary when validating an
|
||||
HSM
|
||||
|
||||
We were doing a "best effort" when validating the HSM token is
|
||||
visible with a valid PIN when it came to groups. A specific
|
||||
workaround was added for softhsm2 but this didn't carry over
|
||||
to other HSMs that may have group-specific read/write access.
|
||||
|
||||
Use the new capability in ipaplatform.constants.py::Group to be
|
||||
able to use generate a valid entry from a group GID. Pair this
|
||||
with os.getgrouplist() and all groups will be passed correctly
|
||||
via ipautil.run().
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9709
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
|
||||
---
|
||||
ipaserver/install/ca.py | 12 ++++--------
|
||||
1 file changed, 4 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py
|
||||
index 520e3fc5de1084e7c22c0cf7eaa86e1d3c421373..2959aceed5cd2fd4851457eaa4aeac3c0905d27d 100644
|
||||
--- a/ipaserver/install/ca.py
|
||||
+++ b/ipaserver/install/ca.py
|
||||
@@ -211,11 +211,7 @@ def hsm_validator(token_name, token_library, token_password):
|
||||
)
|
||||
pkiuser = constants.PKI_USER
|
||||
pkigroup = constants.PKI_GROUP
|
||||
- if 'libsofthsm' in token_library:
|
||||
- import grp
|
||||
- group = grp.getgrnam(constants.ODS_GROUP)
|
||||
- if str(constants.PKI_USER) in group.gr_mem:
|
||||
- pkigroup = constants.ODS_GROUP
|
||||
+ group_list = os.getgrouplist(pkiuser, pkigroup.gid)
|
||||
with certdb.NSSDatabase() as tempnssdb:
|
||||
tempnssdb.create_db(user=str(pkiuser), group=str(pkigroup))
|
||||
# Try adding the token library to the temporary database in
|
||||
@@ -231,7 +227,7 @@ def hsm_validator(token_name, token_library, token_password):
|
||||
# It may fail if p11-kit has already registered the library, that's
|
||||
# ok.
|
||||
ipautil.run(command, stdin='\n', cwd=tempnssdb.secdir,
|
||||
- runas=pkiuser, suplementary_groups=[pkigroup],
|
||||
+ runas=pkiuser, suplementary_groups=group_list,
|
||||
raiseonerr=False)
|
||||
|
||||
command = [
|
||||
@@ -242,7 +238,7 @@ def hsm_validator(token_name, token_library, token_password):
|
||||
]
|
||||
lines = ipautil.run(
|
||||
command, cwd=tempnssdb.secdir, capture_output=True,
|
||||
- runas=pkiuser, suplementary_groups=[pkigroup]).output
|
||||
+ runas=pkiuser, suplementary_groups=group_list).output
|
||||
found = False
|
||||
token_line = f'token: {token_name}'
|
||||
for line in lines.split('\n'):
|
||||
@@ -265,7 +261,7 @@ def hsm_validator(token_name, token_library, token_password):
|
||||
]
|
||||
result = ipautil.run(args, cwd=tempnssdb.secdir,
|
||||
runas=pkiuser,
|
||||
- suplementary_groups=[pkigroup],
|
||||
+ suplementary_groups=group_list,
|
||||
capture_error=True, raiseonerr=False)
|
||||
if result.returncode != 0 and len(result.error_output):
|
||||
if 'SEC_ERROR_BAD_PASSWORD' in result.error_output:
|
||||
--
|
||||
2.47.1
|
||||
|
@ -1,337 +0,0 @@
|
||||
diff --git a/ipaserver/plugins/idrange.py b/ipaserver/plugins/idrange.py
|
||||
index d5b184f..b38ea73 100644
|
||||
--- a/ipaserver/plugins/idrange.py
|
||||
+++ b/ipaserver/plugins/idrange.py
|
||||
@@ -549,6 +549,12 @@ class idrange_add(LDAPCreate):
|
||||
self.obj.handle_ipabaserid(entry_attrs, options)
|
||||
self.obj.handle_iparangetype(entry_attrs, options,
|
||||
keep_objectclass=True)
|
||||
+ self.add_message(
|
||||
+ messages.ServiceRestartRequired(
|
||||
+ service=services.knownservices.dirsrv.service_instance(""),
|
||||
+ server=_('<all IPA servers>')
|
||||
+ )
|
||||
+ )
|
||||
return dn
|
||||
|
||||
|
||||
diff --git a/ipatests/test_xmlrpc/test_range_plugin.py b/ipatests/test_xmlrpc/test_range_plugin.py
|
||||
index f912e04..e3f4c23 100644
|
||||
--- a/ipatests/test_xmlrpc/test_range_plugin.py
|
||||
+++ b/ipatests/test_xmlrpc/test_range_plugin.py
|
||||
@@ -372,6 +372,8 @@ IPA_LOCAL_RANGE_MOD_ERR = (
|
||||
"domain. Run `ipa help idrange` for more information"
|
||||
)
|
||||
|
||||
+dirsrv_instance = services.knownservices.dirsrv.service_instance("")
|
||||
+
|
||||
|
||||
@pytest.mark.tier1
|
||||
class test_range(Declarative):
|
||||
@@ -464,6 +466,11 @@ class test_range(Declarative):
|
||||
),
|
||||
value=testrange1,
|
||||
summary=u'Added ID range "%s"' % (testrange1),
|
||||
+ messages=(
|
||||
+ messages.ServiceRestartRequired(
|
||||
+ service=dirsrv_instance,
|
||||
+ server='<all IPA servers>').to_dict(),
|
||||
+ ),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -633,6 +640,11 @@ class test_range(Declarative):
|
||||
),
|
||||
value=testrange2,
|
||||
summary=u'Added ID range "%s"' % (testrange2),
|
||||
+ messages=(
|
||||
+ messages.ServiceRestartRequired(
|
||||
+ service=dirsrv_instance,
|
||||
+ server='<all IPA servers>').to_dict(),
|
||||
+ ),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -792,6 +804,11 @@ class test_range(Declarative):
|
||||
),
|
||||
value=unicode(domain7range1),
|
||||
summary=u'Added ID range "%s"' % (domain7range1),
|
||||
+ messages=(
|
||||
+ messages.ServiceRestartRequired(
|
||||
+ service=dirsrv_instance,
|
||||
+ server='<all IPA servers>').to_dict(),
|
||||
+ ),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1079,6 +1096,11 @@ class test_range(Declarative):
|
||||
),
|
||||
value=testrange9,
|
||||
summary=u'Added ID range "%s"' % (testrange9),
|
||||
+ messages=(
|
||||
+ messages.ServiceRestartRequired(
|
||||
+ service=dirsrv_instance,
|
||||
+ server='<all IPA servers>').to_dict(),
|
||||
+ ),
|
||||
),
|
||||
),
|
||||
|
||||
diff --git a/ipaserver/plugins/idrange.py b/ipaserver/plugins/idrange.py
|
||||
index b38ea73..b12e1b8 100644
|
||||
--- a/ipaserver/plugins/idrange.py
|
||||
+++ b/ipaserver/plugins/idrange.py
|
||||
@@ -549,12 +549,15 @@ class idrange_add(LDAPCreate):
|
||||
self.obj.handle_ipabaserid(entry_attrs, options)
|
||||
self.obj.handle_iparangetype(entry_attrs, options,
|
||||
keep_objectclass=True)
|
||||
- self.add_message(
|
||||
- messages.ServiceRestartRequired(
|
||||
- service=services.knownservices.dirsrv.service_instance(""),
|
||||
- server=_('<all IPA servers>')
|
||||
+
|
||||
+ if entry_attrs.single_value.get('iparangetype') in (
|
||||
+ 'ipa-local', self.obj.range_types.get('ipa-local', None)):
|
||||
+ self.add_message(
|
||||
+ messages.ServiceRestartRequired(
|
||||
+ service=services.knownservices.dirsrv.service_instance(""),
|
||||
+ server=_('<all IPA servers>')
|
||||
+ )
|
||||
)
|
||||
- )
|
||||
return dn
|
||||
|
||||
|
||||
@@ -568,7 +571,8 @@ class idrange_del(LDAPDelete):
|
||||
try:
|
||||
old_attrs = ldap.get_entry(dn, ['ipabaseid',
|
||||
'ipaidrangesize',
|
||||
- 'ipanttrusteddomainsid'])
|
||||
+ 'ipanttrusteddomainsid',
|
||||
+ 'iparangetype'])
|
||||
except errors.NotFound:
|
||||
raise self.obj.handle_not_found(*keys)
|
||||
|
||||
@@ -602,6 +606,20 @@ class idrange_del(LDAPDelete):
|
||||
key=keys[0],
|
||||
dependent=trust_domains[0].dn[0].value)
|
||||
|
||||
+ self.add_message(
|
||||
+ messages.ServiceRestartRequired(
|
||||
+ service=services.knownservices['sssd'].systemd_name,
|
||||
+ server=_('<all IPA servers>')
|
||||
+ )
|
||||
+ )
|
||||
+
|
||||
+ if old_attrs.single_value.get('iparangetype') == 'ipa-local':
|
||||
+ self.add_message(
|
||||
+ messages.ServiceRestartRequired(
|
||||
+ service=services.knownservices.dirsrv.service_instance(""),
|
||||
+ server=_('<all IPA servers>')
|
||||
+ )
|
||||
+ )
|
||||
|
||||
return dn
|
||||
|
||||
@@ -804,10 +822,20 @@ class idrange_mod(LDAPUpdate):
|
||||
assert isinstance(dn, DN)
|
||||
self.obj.handle_ipabaserid(entry_attrs, options)
|
||||
self.obj.handle_iparangetype(entry_attrs, options)
|
||||
+
|
||||
+ if entry_attrs.single_value.get('iparangetype') in (
|
||||
+ 'ipa-local', self.obj.range_types.get('ipa-local', None)):
|
||||
+ self.add_message(
|
||||
+ messages.ServiceRestartRequired(
|
||||
+ service=services.knownservices.dirsrv.service_instance(""),
|
||||
+ server=_('<all IPA servers>')
|
||||
+ )
|
||||
+ )
|
||||
+
|
||||
self.add_message(
|
||||
messages.ServiceRestartRequired(
|
||||
service=services.knownservices['sssd'].systemd_name,
|
||||
- server=keys[0]
|
||||
+ server=_('<all IPA servers>')
|
||||
)
|
||||
)
|
||||
return dn
|
||||
diff --git a/ipatests/test_xmlrpc/test_range_plugin.py b/ipatests/test_xmlrpc/test_range_plugin.py
|
||||
index e3f4c23..531fe4a 100644
|
||||
--- a/ipatests/test_xmlrpc/test_range_plugin.py
|
||||
+++ b/ipatests/test_xmlrpc/test_range_plugin.py
|
||||
@@ -26,7 +26,8 @@ import six
|
||||
from ipalib import api, errors, messages
|
||||
from ipalib import constants
|
||||
from ipaplatform import services
|
||||
-from ipatests.test_xmlrpc.xmlrpc_test import Declarative, fuzzy_uuid
|
||||
+from ipatests.test_xmlrpc.xmlrpc_test import (
|
||||
+ Declarative, fuzzy_uuid, Fuzzy, fuzzy_sequence_of)
|
||||
from ipatests.test_xmlrpc import objectclasses
|
||||
from ipatests.util import MockLDAP
|
||||
from ipapython.dn import DN
|
||||
@@ -374,6 +375,8 @@ IPA_LOCAL_RANGE_MOD_ERR = (
|
||||
|
||||
dirsrv_instance = services.knownservices.dirsrv.service_instance("")
|
||||
|
||||
+fuzzy_restart_messages = fuzzy_sequence_of(Fuzzy(type=dict))
|
||||
+
|
||||
|
||||
@pytest.mark.tier1
|
||||
class test_range(Declarative):
|
||||
@@ -610,7 +613,8 @@ class test_range(Declarative):
|
||||
desc='Delete ID range %r' % testrange1,
|
||||
command=('idrange_del', [testrange1], {}),
|
||||
expected=dict(
|
||||
- result=dict(failed=[]),
|
||||
+ result=dict(failed=[],
|
||||
+ messages=fuzzy_restart_messages),
|
||||
value=[testrange1],
|
||||
summary=u'Deleted ID range "%s"' % testrange1,
|
||||
),
|
||||
@@ -714,7 +718,8 @@ class test_range(Declarative):
|
||||
desc='Delete ID range %r' % testrange2,
|
||||
command=('idrange_del', [testrange2], {}),
|
||||
expected=dict(
|
||||
- result=dict(failed=[]),
|
||||
+ result=dict(failed=[],
|
||||
+ messages=fuzzy_restart_messages),
|
||||
value=[testrange2],
|
||||
summary=u'Deleted ID range "%s"' % testrange2,
|
||||
),
|
||||
diff --git a/ipatests/test_xmlrpc/test_range_plugin.py b/ipatests/test_xmlrpc/test_range_plugin.py
|
||||
index 531fe4a..3646952 100644
|
||||
--- a/ipatests/test_xmlrpc/test_range_plugin.py
|
||||
+++ b/ipatests/test_xmlrpc/test_range_plugin.py
|
||||
@@ -613,8 +613,8 @@ class test_range(Declarative):
|
||||
desc='Delete ID range %r' % testrange1,
|
||||
command=('idrange_del', [testrange1], {}),
|
||||
expected=dict(
|
||||
- result=dict(failed=[],
|
||||
- messages=fuzzy_restart_messages),
|
||||
+ result=dict(failed=[]),
|
||||
+ messages=fuzzy_restart_messages,
|
||||
value=[testrange1],
|
||||
summary=u'Deleted ID range "%s"' % testrange1,
|
||||
),
|
||||
@@ -718,8 +718,8 @@ class test_range(Declarative):
|
||||
desc='Delete ID range %r' % testrange2,
|
||||
command=('idrange_del', [testrange2], {}),
|
||||
expected=dict(
|
||||
- result=dict(failed=[],
|
||||
- messages=fuzzy_restart_messages),
|
||||
+ result=dict(failed=[]),
|
||||
+ messages=fuzzy_restart_messages,
|
||||
value=[testrange2],
|
||||
summary=u'Deleted ID range "%s"' % testrange2,
|
||||
),
|
||||
@@ -809,11 +809,6 @@ class test_range(Declarative):
|
||||
),
|
||||
value=unicode(domain7range1),
|
||||
summary=u'Added ID range "%s"' % (domain7range1),
|
||||
- messages=(
|
||||
- messages.ServiceRestartRequired(
|
||||
- service=dirsrv_instance,
|
||||
- server='<all IPA servers>').to_dict(),
|
||||
- ),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -836,6 +831,7 @@ class test_range(Declarative):
|
||||
result=dict(failed=[]),
|
||||
value=[domain1range1],
|
||||
summary=u'Deleted ID range "%s"' % domain1range1,
|
||||
+ messages=fuzzy_restart_messages,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -862,12 +858,7 @@ class test_range(Declarative):
|
||||
command=('idrange_mod', [domain3range2],
|
||||
dict(ipabaseid=domain3range1_base_id)),
|
||||
expected=dict(
|
||||
- messages=(
|
||||
- messages.ServiceRestartRequired(
|
||||
- service=services.knownservices['sssd'].systemd_name,
|
||||
- server=domain3range2
|
||||
- ).to_dict(),
|
||||
- ),
|
||||
+ messages=fuzzy_restart_messages,
|
||||
result=dict(
|
||||
cn=[domain3range2],
|
||||
ipabaseid=[unicode(domain3range1_base_id)],
|
||||
@@ -933,12 +924,7 @@ class test_range(Declarative):
|
||||
command=('idrange_mod', [domain2range1],
|
||||
dict(ipabaserid=domain5range1_base_rid)),
|
||||
expected=dict(
|
||||
- messages=(
|
||||
- messages.ServiceRestartRequired(
|
||||
- service=services.knownservices['sssd'].systemd_name,
|
||||
- server=domain2range1
|
||||
- ).to_dict(),
|
||||
- ),
|
||||
+ messages=fuzzy_restart_messages,
|
||||
result=dict(
|
||||
cn=[domain2range1],
|
||||
ipabaseid=[unicode(domain2range1_base_id)],
|
||||
@@ -973,12 +959,7 @@ class test_range(Declarative):
|
||||
command=('idrange_mod', [domain2range1],
|
||||
dict(ipaautoprivategroups='true')),
|
||||
expected=dict(
|
||||
- messages=(
|
||||
- messages.ServiceRestartRequired(
|
||||
- service=services.knownservices['sssd'].systemd_name,
|
||||
- server=domain2range1
|
||||
- ).to_dict(),
|
||||
- ),
|
||||
+ messages=fuzzy_restart_messages,
|
||||
result=dict(
|
||||
cn=[domain2range1],
|
||||
ipabaseid=[unicode(domain2range1_base_id)],
|
||||
@@ -1000,12 +981,7 @@ class test_range(Declarative):
|
||||
command=('idrange_mod', [domain2range1],
|
||||
dict(ipaautoprivategroups='false')),
|
||||
expected=dict(
|
||||
- messages=(
|
||||
- messages.ServiceRestartRequired(
|
||||
- service=services.knownservices['sssd'].systemd_name,
|
||||
- server=domain2range1
|
||||
- ).to_dict(),
|
||||
- ),
|
||||
+ messages=fuzzy_restart_messages,
|
||||
result=dict(
|
||||
cn=[domain2range1],
|
||||
ipabaseid=[unicode(domain2range1_base_id)],
|
||||
@@ -1027,12 +1003,7 @@ class test_range(Declarative):
|
||||
command=('idrange_mod', [domain2range1],
|
||||
dict(ipaautoprivategroups='hybrid')),
|
||||
expected=dict(
|
||||
- messages=(
|
||||
- messages.ServiceRestartRequired(
|
||||
- service=services.knownservices['sssd'].systemd_name,
|
||||
- server=domain2range1
|
||||
- ).to_dict(),
|
||||
- ),
|
||||
+ messages=fuzzy_restart_messages,
|
||||
result=dict(
|
||||
cn=[domain2range1],
|
||||
ipabaseid=[unicode(domain2range1_base_id)],
|
||||
@@ -1054,12 +1025,7 @@ class test_range(Declarative):
|
||||
command=('idrange_mod', [domain2range1],
|
||||
dict(ipaautoprivategroups='')),
|
||||
expected=dict(
|
||||
- messages=(
|
||||
- messages.ServiceRestartRequired(
|
||||
- service=services.knownservices['sssd'].systemd_name,
|
||||
- server=domain2range1
|
||||
- ).to_dict(),
|
||||
- ),
|
||||
+ messages=fuzzy_restart_messages,
|
||||
result=dict(
|
||||
cn=[domain2range1],
|
||||
ipabaseid=[unicode(domain2range1_base_id)],
|
||||
@@ -1116,6 +1082,7 @@ class test_range(Declarative):
|
||||
result=dict(failed=[]),
|
||||
value=[testrange9],
|
||||
summary=u'Deleted ID range "%s"' % testrange9,
|
||||
+ messages=fuzzy_restart_messages,
|
||||
),
|
||||
),
|
||||
|
@ -1,58 +0,0 @@
|
||||
diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py
|
||||
index 619be83..9be1b67 100644
|
||||
--- a/ipaserver/plugins/cert.py
|
||||
+++ b/ipaserver/plugins/cert.py
|
||||
@@ -55,7 +55,7 @@ from ipapython.dn import DN
|
||||
from ipapython.ipautil import datetime_from_utctimestamp
|
||||
from ipaserver.plugins.service import normalize_principal, validate_realm
|
||||
from ipaserver.masters import (
|
||||
- ENABLED_SERVICE, CONFIGURED_SERVICE, is_service_enabled
|
||||
+ ENABLED_SERVICE, CONFIGURED_SERVICE, HIDDEN_SERVICE, is_service_enabled
|
||||
)
|
||||
|
||||
try:
|
||||
@@ -300,7 +300,7 @@ def caacl_check(principal, ca, profile_id):
|
||||
def ca_kdc_check(api_instance, hostname):
|
||||
master_dn = api_instance.Object.server.get_dn(unicode(hostname))
|
||||
kdc_dn = DN(('cn', 'KDC'), master_dn)
|
||||
- wanted = {ENABLED_SERVICE, CONFIGURED_SERVICE}
|
||||
+ wanted = {ENABLED_SERVICE, CONFIGURED_SERVICE, HIDDEN_SERVICE}
|
||||
try:
|
||||
kdc_entry = api_instance.Backend.ldap2.get_entry(
|
||||
kdc_dn, ['ipaConfigString'])
|
||||
diff --git a/ipatests/test_integration/test_replica_promotion.py b/ipatests/test_integration/test_replica_promotion.py
|
||||
index b71f2d5..7ef44c5 100644
|
||||
--- a/ipatests/test_integration/test_replica_promotion.py
|
||||
+++ b/ipatests/test_integration/test_replica_promotion.py
|
||||
@@ -26,6 +26,7 @@ from ipalib.constants import (
|
||||
)
|
||||
from ipaplatform.paths import paths
|
||||
from ipapython import certdb
|
||||
+from ipatests.test_integration.test_cert import get_certmonger_fs_id
|
||||
from ipatests.test_integration.test_dns_locations import (
|
||||
resolve_records_from_server, IPA_DEFAULT_MASTER_SRV_REC
|
||||
)
|
||||
@@ -1241,6 +1242,23 @@ class TestHiddenReplicaPromotion(IntegrationTest):
|
||||
'ipa-crlgen-manage', 'status'])
|
||||
assert "CRL generation: enabled" in result.stdout_text
|
||||
|
||||
+ def test_hidden_replica_renew_pkinit_cert(self):
|
||||
+ """Renew the PKINIT cert on a hidden replica.
|
||||
+
|
||||
+ Test for https://pagure.io/freeipa/issue/9611
|
||||
+ """
|
||||
+ # Get Request ID
|
||||
+ cmd = ['getcert', 'list', '-f', paths.KDC_CERT]
|
||||
+ result = self.replicas[0].run_command(cmd)
|
||||
+ req_id = get_certmonger_fs_id(result.stdout_text)
|
||||
+
|
||||
+ self.replicas[0].run_command([
|
||||
+ 'getcert', 'resubmit', '-f', paths.KDC_CERT
|
||||
+ ])
|
||||
+ tasks.wait_for_certmonger_status(
|
||||
+ self.replicas[0], ('MONITORING'), req_id, timeout=600
|
||||
+ )
|
||||
+
|
||||
|
||||
class TestHiddenReplicaKRA(IntegrationTest):
|
||||
"""Test KRA & hidden replica features.
|
166
SOURCES/0033-ipalib-x509-support-PyCA-44.0.patch
Normal file
166
SOURCES/0033-ipalib-x509-support-PyCA-44.0.patch
Normal file
@ -0,0 +1,166 @@
|
||||
From d4d56a6705c870901bc73882e4804367f7c9c91a Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Sun, 1 Dec 2024 20:16:54 +0200
|
||||
Subject: [PATCH] ipalib/x509: support PyCA 44.0
|
||||
|
||||
PyCA made x509.Certificate class concrete, it cannot be extended anymore
|
||||
by Python code. The intent is to use helper functions to instantiate
|
||||
certificate objects and never create them directly.
|
||||
|
||||
FreeIPA wraps PyCA's x509.Certificate class and provides own shim
|
||||
on top of it. In most cases we load the certificate content via the
|
||||
helper functions and don't really need to derive from the certificate
|
||||
class.
|
||||
|
||||
Move IPACertificate to be a normal Python object class that stores
|
||||
x509.Certificate internally. The only place where this breaks is when
|
||||
IPACertificate object needs to be passed to a code that expects
|
||||
x509.Certificate (Dogtag PKI). In such cases, expose the underlying
|
||||
certificate instance via IPACertificate.cert property.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9708
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
---
|
||||
ipalib/ipajson.py | 4 ++--
|
||||
ipalib/x509.py | 10 +++++++++-
|
||||
ipapython/ipaldap.py | 15 +++++++--------
|
||||
ipaserver/plugins/dogtag.py | 3 ++-
|
||||
4 files changed, 20 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/ipalib/ipajson.py b/ipalib/ipajson.py
|
||||
index 5551d12e5fec7e458fa6fe85560664b2fd897337..fd99c8219c722c52321336f28ff27e1573e906c7 100644
|
||||
--- a/ipalib/ipajson.py
|
||||
+++ b/ipalib/ipajson.py
|
||||
@@ -9,7 +9,7 @@ from decimal import Decimal
|
||||
import json
|
||||
import six
|
||||
from ipalib.constants import LDAP_GENERALIZED_TIME_FORMAT
|
||||
-from ipalib import capabilities
|
||||
+from ipalib import capabilities, x509
|
||||
from ipalib.x509 import Encoding as x509_Encoding
|
||||
from ipapython.dn import DN
|
||||
from ipapython.dnsutil import DNSName
|
||||
@@ -72,7 +72,7 @@ class _JSONPrimer(dict):
|
||||
list: self._enc_list,
|
||||
tuple: self._enc_list,
|
||||
dict: self._enc_dict,
|
||||
- crypto_x509.Certificate: self._enc_certificate,
|
||||
+ x509.IPACertificate: self._enc_certificate,
|
||||
crypto_x509.CertificateSigningRequest: self._enc_certificate,
|
||||
})
|
||||
|
||||
diff --git a/ipalib/x509.py b/ipalib/x509.py
|
||||
index fd08238962b2b5e9cd056fb13c0a81ee8f31b092..6780bead00b50efdf03c62ce717572eeb9df2e5f 100644
|
||||
--- a/ipalib/x509.py
|
||||
+++ b/ipalib/x509.py
|
||||
@@ -88,7 +88,7 @@ SAN_UPN = '1.3.6.1.4.1.311.20.2.3'
|
||||
SAN_KRB5PRINCIPALNAME = '1.3.6.1.5.2.2'
|
||||
|
||||
|
||||
-class IPACertificate(crypto_x509.Certificate):
|
||||
+class IPACertificate:
|
||||
"""
|
||||
A proxy class wrapping a python-cryptography certificate representation for
|
||||
IPA purposes
|
||||
@@ -205,6 +205,10 @@ class IPACertificate(crypto_x509.Certificate):
|
||||
"""
|
||||
return self._cert.fingerprint(algorithm)
|
||||
|
||||
+ @property
|
||||
+ def cert(self):
|
||||
+ return self._cert
|
||||
+
|
||||
@property
|
||||
def serial_number(self):
|
||||
return self._cert.serial_number
|
||||
@@ -457,6 +461,8 @@ def load_pem_x509_certificate(data):
|
||||
:returns: a ``IPACertificate`` object.
|
||||
:raises: ``ValueError`` if unable to load the certificate.
|
||||
"""
|
||||
+ if isinstance(data, IPACertificate):
|
||||
+ return data
|
||||
return IPACertificate(
|
||||
crypto_x509.load_pem_x509_certificate(data, backend=default_backend())
|
||||
)
|
||||
@@ -469,6 +475,8 @@ def load_der_x509_certificate(data):
|
||||
:returns: a ``IPACertificate`` object.
|
||||
:raises: ``ValueError`` if unable to load the certificate.
|
||||
"""
|
||||
+ if isinstance(data, IPACertificate):
|
||||
+ return data
|
||||
return IPACertificate(
|
||||
crypto_x509.load_der_x509_certificate(data, backend=default_backend())
|
||||
)
|
||||
diff --git a/ipapython/ipaldap.py b/ipapython/ipaldap.py
|
||||
index 1888e40916aa6e641542f08fb30ff2b0d4b850b1..5bb81c1bc844fce9b14251d3702e09099d85cdb5 100644
|
||||
--- a/ipapython/ipaldap.py
|
||||
+++ b/ipapython/ipaldap.py
|
||||
@@ -33,7 +33,6 @@ import warnings
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
-from cryptography import x509 as crypto_x509
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
|
||||
import ldap
|
||||
@@ -748,10 +747,10 @@ class LDAPClient:
|
||||
'dnszoneidnsname': DNSName,
|
||||
'krbcanonicalname': Principal,
|
||||
'krbprincipalname': Principal,
|
||||
- 'usercertificate': crypto_x509.Certificate,
|
||||
- 'usercertificate;binary': crypto_x509.Certificate,
|
||||
- 'cACertificate': crypto_x509.Certificate,
|
||||
- 'cACertificate;binary': crypto_x509.Certificate,
|
||||
+ 'usercertificate': x509.IPACertificate,
|
||||
+ 'usercertificate;binary': x509.IPACertificate,
|
||||
+ 'cACertificate': x509.IPACertificate,
|
||||
+ 'cACertificate;binary': x509.IPACertificate,
|
||||
'nsds5replicalastupdatestart': unicode,
|
||||
'nsds5replicalastupdateend': unicode,
|
||||
'nsds5replicalastinitstart': unicode,
|
||||
@@ -1000,7 +999,7 @@ class LDAPClient:
|
||||
return dct
|
||||
elif isinstance(val, datetime):
|
||||
return val.strftime(LDAP_GENERALIZED_TIME_FORMAT).encode('utf-8')
|
||||
- elif isinstance(val, crypto_x509.Certificate):
|
||||
+ elif isinstance(val, x509.IPACertificate):
|
||||
return val.public_bytes(x509.Encoding.DER)
|
||||
elif val is None:
|
||||
return None
|
||||
@@ -1027,7 +1026,7 @@ class LDAPClient:
|
||||
return DNSName.from_text(val.decode('utf-8'))
|
||||
elif target_type in (DN, Principal):
|
||||
return target_type(val.decode('utf-8'))
|
||||
- elif target_type is crypto_x509.Certificate:
|
||||
+ elif target_type is x509.IPACertificate:
|
||||
return x509.load_der_x509_certificate(val)
|
||||
else:
|
||||
return target_type(val)
|
||||
@@ -1381,7 +1380,7 @@ class LDAPClient:
|
||||
]
|
||||
return cls.combine_filters(flts, rules)
|
||||
elif value is not None:
|
||||
- if isinstance(value, crypto_x509.Certificate):
|
||||
+ if isinstance(value, x509.IPACertificate):
|
||||
value = value.public_bytes(serialization.Encoding.DER)
|
||||
if isinstance(value, bytes):
|
||||
value = binascii.hexlify(value).decode('ascii')
|
||||
diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py
|
||||
index 78afb279795ecf74f296cbbb8724505075a6e4a9..ee6d0e347d640a2664e38ba64785c3d8af54bbad 100644
|
||||
--- a/ipaserver/plugins/dogtag.py
|
||||
+++ b/ipaserver/plugins/dogtag.py
|
||||
@@ -1581,7 +1581,8 @@ class kra(Backend):
|
||||
|
||||
crypto = cryptoutil.CryptographyCryptoProvider(
|
||||
transport_cert_nick="ra_agent",
|
||||
- transport_cert=x509.load_certificate_from_file(paths.RA_AGENT_PEM)
|
||||
+ transport_cert=x509.load_certificate_from_file(
|
||||
+ paths.RA_AGENT_PEM).cert
|
||||
)
|
||||
|
||||
# TODO: obtain KRA host & port from IPA service list or point to KRA load balancer
|
||||
--
|
||||
2.47.1
|
||||
|
120
SOURCES/0034-pyca-adapt-import-paths-for-TripleDES-cipher.patch
Normal file
120
SOURCES/0034-pyca-adapt-import-paths-for-TripleDES-cipher.patch
Normal file
@ -0,0 +1,120 @@
|
||||
From 8dfec28647f7c17e47fbfc96a1720dcde1592386 Mon Sep 17 00:00:00 2001
|
||||
From: Stanislav Levin <slev@altlinux.org>
|
||||
Date: Mon, 2 Dec 2024 15:04:30 +0300
|
||||
Subject: [PATCH] pyca: adapt import paths for TripleDES cipher
|
||||
|
||||
https://cryptography.io/en/latest/hazmat/primitives/symmetric-encryption/#cryptography.hazmat.primitives.ciphers.algorithms.TripleDES
|
||||
|
||||
> This algorithm has been deprecated and moved to the Decrepit
|
||||
cryptography module. If you need to continue using it then update your
|
||||
code to use the new module path. It will be removed from this namespace
|
||||
in 48.0.0.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9708
|
||||
Signed-off-by: Stanislav Levin <slev@altlinux.org>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
---
|
||||
ipaclient/plugins/vault.py | 8 +++++++-
|
||||
ipalib/constants.py | 24 +++++++++++-------------
|
||||
ipaserver/install/ipa_otptoken_import.py | 8 +++++++-
|
||||
3 files changed, 25 insertions(+), 15 deletions(-)
|
||||
|
||||
diff --git a/ipaclient/plugins/vault.py b/ipaclient/plugins/vault.py
|
||||
index 75415c03a57242ae674636fa31a72db2fa56d6ea..6af7297936924dfb80e7f79924b570421da65c97 100644
|
||||
--- a/ipaclient/plugins/vault.py
|
||||
+++ b/ipaclient/plugins/vault.py
|
||||
@@ -34,6 +34,12 @@ from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
||||
from cryptography.hazmat.primitives.asymmetric import padding
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
+try:
|
||||
+ # cryptography>=43.0.0
|
||||
+ from cryptography.hazmat.decrepit.ciphers.algorithms import TripleDES
|
||||
+except ImportError:
|
||||
+ # will be removed from this module in cryptography 48.0.0
|
||||
+ from cryptography.hazmat.primitives.ciphers.algorithms import TripleDES
|
||||
from cryptography.hazmat.primitives.padding import PKCS7
|
||||
from cryptography.hazmat.primitives.serialization import (
|
||||
load_pem_public_key, load_pem_private_key)
|
||||
@@ -661,7 +667,7 @@ class ModVaultData(Local):
|
||||
if name == constants.VAULT_WRAPPING_AES128_CBC:
|
||||
return algorithms.AES(os.urandom(128 // 8))
|
||||
elif name == constants.VAULT_WRAPPING_3DES:
|
||||
- return algorithms.TripleDES(os.urandom(196 // 8))
|
||||
+ return TripleDES(os.urandom(196 // 8))
|
||||
else:
|
||||
# unreachable
|
||||
raise ValueError(name)
|
||||
diff --git a/ipalib/constants.py b/ipalib/constants.py
|
||||
index b657e5a9065d115d0eff2dbfffff49e992006536..c90caa22149ec3d93d45fcb5480f7401e4555799 100644
|
||||
--- a/ipalib/constants.py
|
||||
+++ b/ipalib/constants.py
|
||||
@@ -25,20 +25,19 @@ All constants centralised in one file.
|
||||
import os
|
||||
import string
|
||||
import uuid
|
||||
-import warnings
|
||||
-
|
||||
-warnings.filterwarnings(
|
||||
- "ignore",
|
||||
- "TripleDES has been moved to "
|
||||
- "cryptography.hazmat.decrepit.ciphers.algorithms.TripleDES and "
|
||||
- "will be removed from this module in 48.0.0",
|
||||
- category=UserWarning)
|
||||
|
||||
from ipaplatform.constants import constants as _constants
|
||||
from ipapython.dn import DN
|
||||
from ipapython.fqdn import gethostfqdn
|
||||
from ipapython.version import VERSION, API_VERSION
|
||||
-from cryptography.hazmat.primitives.ciphers import algorithms, modes
|
||||
+from cryptography.hazmat.primitives.ciphers import modes
|
||||
+try:
|
||||
+ # cryptography>=43.0.0
|
||||
+ from cryptography.hazmat.decrepit.ciphers.algorithms import TripleDES
|
||||
+except ImportError:
|
||||
+ # will be removed from this module in cryptography 48.0.0
|
||||
+ from cryptography.hazmat.primitives.ciphers.algorithms import TripleDES
|
||||
+
|
||||
from cryptography.hazmat.backends.openssl.backend import backend
|
||||
|
||||
|
||||
@@ -389,7 +388,6 @@ VAULT_WRAPPING_SUPPORTED_ALGOS = (
|
||||
VAULT_WRAPPING_DEFAULT_ALGO = VAULT_WRAPPING_AES128_CBC
|
||||
|
||||
# Add 3DES for backwards compatibility if supported
|
||||
-if getattr(algorithms, 'TripleDES', None):
|
||||
- if backend.cipher_supported(algorithms.TripleDES(
|
||||
- b"\x00" * 8), modes.CBC(b"\x00" * 8)):
|
||||
- VAULT_WRAPPING_SUPPORTED_ALGOS += (VAULT_WRAPPING_3DES,)
|
||||
+if backend.cipher_supported(TripleDES(
|
||||
+ b"\x00" * 8), modes.CBC(b"\x00" * 8)):
|
||||
+ VAULT_WRAPPING_SUPPORTED_ALGOS += (VAULT_WRAPPING_3DES,)
|
||||
diff --git a/ipaserver/install/ipa_otptoken_import.py b/ipaserver/install/ipa_otptoken_import.py
|
||||
index 279a7502d2f305309252b3b291e32b772a51a1d3..17457f6c5b81ab70a0ecee13bf744e242ec88ff0 100644
|
||||
--- a/ipaserver/install/ipa_otptoken_import.py
|
||||
+++ b/ipaserver/install/ipa_otptoken_import.py
|
||||
@@ -37,6 +37,12 @@ from cryptography.hazmat.primitives import hashes, hmac
|
||||
from cryptography.hazmat.primitives.padding import PKCS7
|
||||
from cryptography.hazmat.primitives.kdf import pbkdf2
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
+try:
|
||||
+ # cryptography>=43.0.0
|
||||
+ from cryptography.hazmat.decrepit.ciphers.algorithms import TripleDES
|
||||
+except ImportError:
|
||||
+ # will be removed from this module in cryptography 48.0.0
|
||||
+ from cryptography.hazmat.primitives.ciphers.algorithms import TripleDES
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
from ipaplatform.paths import paths
|
||||
@@ -169,7 +175,7 @@ def convertAlgorithm(value):
|
||||
# in the list of the vault wrapping algorithms, we cannot use 3DES anywhere
|
||||
if VAULT_WRAPPING_3DES in VAULT_WRAPPING_SUPPORTED_ALGOS:
|
||||
supported_algs["http://www.w3.org/2001/04/xmlenc#tripledes-cbc"] = (
|
||||
- algorithms.TripleDES, modes.CBC, 64)
|
||||
+ TripleDES, modes.CBC, 64)
|
||||
|
||||
return supported_algs.get(value.lower(), (None, None, None))
|
||||
|
||||
--
|
||||
2.47.1
|
||||
|
134
SOURCES/0035-ipa-pwd-extop-clarify-OTP-use-over-LDAP-binds.patch
Normal file
134
SOURCES/0035-ipa-pwd-extop-clarify-OTP-use-over-LDAP-binds.patch
Normal file
@ -0,0 +1,134 @@
|
||||
From 3e7ec3dc49d0f559bdbe330e52019e59f0b57c18 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Tue, 3 Dec 2024 18:06:45 +0200
|
||||
Subject: [PATCH] ipa-pwd-extop: clarify OTP use over LDAP binds
|
||||
|
||||
OTP use during LDAP bind can be enforced either explicitly via client
|
||||
specifying a control with OID 2.16.840.1.113730.3.8.10.7 and no payload
|
||||
or implicitly through the global IPA configuration with EnforceLDAPOTP.
|
||||
|
||||
OTP token enforcement overrides IPA user authentication types
|
||||
requirements:
|
||||
|
||||
If OTP enforcement is required:
|
||||
|
||||
- if user authentication types still allow password authentication,
|
||||
authentication with just a password is denied, regardless whether OTP
|
||||
tokens are associated with the user or not.
|
||||
|
||||
If OTP enforcement is not required:
|
||||
|
||||
- if user has no OTP tokens but user authentication types require OTP
|
||||
use, authentication with just a password is allowed until a token is
|
||||
added.
|
||||
|
||||
- if user has OTP tokens and user authentication types require OTP use
|
||||
but not password, authentication with just a password is denied.
|
||||
|
||||
Additionally, enforcement of OTP only applies to LDAP objects which
|
||||
don't use 'simpleSecurityObject' objectclass. This allows system service
|
||||
accounts to continue authenticate with a password regardless of the
|
||||
OTP enforcement.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9699
|
||||
Fixes: https://pagure.io/freeipa/issue/9711
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
.../ipa-slapi-plugins/ipa-pwd-extop/prepost.c | 38 +++++++++++++++----
|
||||
1 file changed, 30 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c
|
||||
index 1c1340e31ac30cb01412a7065ea339cb5461e839..42e880fd0a5c8b4708b145b340209eb218f60c4e 100644
|
||||
--- a/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c
|
||||
+++ b/daemons/ipa-slapi-plugins/ipa-pwd-extop/prepost.c
|
||||
@@ -1219,12 +1219,10 @@ typedef enum {
|
||||
} otp_req_enum;
|
||||
static bool ipapwd_pre_bind_otp(const char *bind_dn, Slapi_Entry *entry,
|
||||
struct berval *creds, otp_req_enum otpreq,
|
||||
- bool *notokens)
|
||||
+ bool *notokens, uint32_t *auth_types)
|
||||
{
|
||||
- uint32_t auth_types;
|
||||
-
|
||||
/* Get the configured authentication types. */
|
||||
- auth_types = otp_config_auth_types(otp_config, entry);
|
||||
+ *auth_types = otp_config_auth_types(otp_config, entry);
|
||||
*notokens = false;
|
||||
|
||||
/*
|
||||
@@ -1237,7 +1235,8 @@ static bool ipapwd_pre_bind_otp(const char *bind_dn, Slapi_Entry *entry,
|
||||
* 2. If PWD is enabled or OTP succeeded, fall through to PWD validation.
|
||||
*/
|
||||
|
||||
- if (auth_types & OTP_CONFIG_AUTH_TYPE_OTP) {
|
||||
+ if ((*auth_types & OTP_CONFIG_AUTH_TYPE_OTP) ||
|
||||
+ (otpreq != OTP_IS_NOT_REQUIRED)) {
|
||||
struct otp_token **tokens = NULL;
|
||||
|
||||
LOG_PLUGIN_NAME(IPAPWD_PLUGIN_NAME,
|
||||
@@ -1270,7 +1269,7 @@ static bool ipapwd_pre_bind_otp(const char *bind_dn, Slapi_Entry *entry,
|
||||
otp_token_free_array(tokens);
|
||||
}
|
||||
|
||||
- return (auth_types & OTP_CONFIG_AUTH_TYPE_PASSWORD) &&
|
||||
+ return (*auth_types & OTP_CONFIG_AUTH_TYPE_PASSWORD) &&
|
||||
(otpreq == OTP_IS_NOT_REQUIRED);
|
||||
}
|
||||
|
||||
@@ -1451,6 +1450,7 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
|
||||
struct ipapwd_krbcfg *krbcfg = NULL;
|
||||
struct berval *credentials = NULL;
|
||||
Slapi_Entry *entry = NULL;
|
||||
+ Slapi_Value *objectclass = NULL;
|
||||
Slapi_DN *target_sdn = NULL;
|
||||
Slapi_DN *sdn = NULL;
|
||||
const char *dn = NULL;
|
||||
@@ -1465,6 +1465,7 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
|
||||
int rc = LDAP_INVALID_CREDENTIALS;
|
||||
char *errMesg = NULL;
|
||||
bool notokens = false;
|
||||
+ uint32_t auth_types = 0;
|
||||
|
||||
/* get BIND parameters */
|
||||
ret |= slapi_pblock_get(pb, SLAPI_BIND_TARGET_SDN, &target_sdn);
|
||||
@@ -1538,12 +1539,33 @@ static int ipapwd_pre_bind(Slapi_PBlock *pb)
|
||||
otpreq = OTP_IS_REQUIRED_IMPLICITLY;
|
||||
}
|
||||
}
|
||||
+ /* we only apply OTP policy to Kerberos principals */
|
||||
+ objectclass = slapi_value_new_string("krbprincipalaux");
|
||||
+ if (objectclass == NULL) {
|
||||
+ goto invalid_creds;
|
||||
+ }
|
||||
+ if (!slapi_entry_attr_has_syntax_value(entry, SLAPI_ATTR_OBJECTCLASS,
|
||||
+ objectclass)) {
|
||||
+ otpreq = OTP_IS_NOT_REQUIRED;
|
||||
+ }
|
||||
+ slapi_value_free(&objectclass);
|
||||
+
|
||||
if (!syncreq && !ipapwd_pre_bind_otp(dn, entry,
|
||||
- credentials, otpreq, ¬okens)) {
|
||||
+ credentials, otpreq,
|
||||
+ ¬okens, &auth_types)) {
|
||||
/* We got here because ipapwd_pre_bind_otp() returned false,
|
||||
* it means that either token verification failed or
|
||||
* a rule for empty tokens failed current policy. */
|
||||
- if (!(notokens || (otpreq == OTP_IS_NOT_REQUIRED)))
|
||||
+
|
||||
+ /* Check if there were any tokens associated, thus
|
||||
+ * OTP token verification has really failed */
|
||||
+ if (notokens == false)
|
||||
+ goto invalid_creds;
|
||||
+
|
||||
+ /* No tokens, check if auth type does not include OTP but OTP is
|
||||
+ * enforced by the current policy */
|
||||
+ if (!(auth_types & OTP_CONFIG_AUTH_TYPE_OTP) &&
|
||||
+ (otpreq != OTP_IS_NOT_REQUIRED))
|
||||
goto invalid_creds;
|
||||
}
|
||||
|
||||
--
|
||||
2.47.1
|
||||
|
@ -0,0 +1,45 @@
|
||||
From 477dbba18bf987bf4461fdfdfba0d497159db7ce Mon Sep 17 00:00:00 2001
|
||||
From: Stanislav Levin <slev@altlinux.org>
|
||||
Date: Wed, 4 Dec 2024 19:56:51 +0300
|
||||
Subject: [PATCH] adtrust: add missing ipaAllowedOperations objectclass
|
||||
|
||||
Per @abbra explanation:
|
||||
> When expected Kerberos principal names for this object were flipped to
|
||||
follow requirements for cross-realm krbtgt objects expected by Active
|
||||
Directory, trusted object changed its canonical Kerberos principal name.
|
||||
The keytab for this Kerberos principal name is fetched by SSSD and it
|
||||
needs to be permitted to read the key. We added the virtual permission
|
||||
to allow the keytab retrieval but didn't add the objectclass that
|
||||
actually allows adding an LDAP attribute to express the permission. When
|
||||
an attribute is added to an LDAP object, objectclasses of the object
|
||||
must allow presence of that attribute.
|
||||
|
||||
This is the followup to #9471 and fixes the upgrade.
|
||||
|
||||
Thanks @abbra!
|
||||
|
||||
Related: https://pagure.io/freeipa/issue/9471
|
||||
Fixes: https://pagure.io/freeipa/issue/9712
|
||||
Signed-off-by: Stanislav Levin <slev@altlinux.org>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
---
|
||||
ipaserver/install/plugins/adtrust.py | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py
|
||||
index e6d49cb2512bff7dcce57f019ecb6c497d11ed52..ab3d427ef561aeb26eb098270446640ba451c8ad 100644
|
||||
--- a/ipaserver/install/plugins/adtrust.py
|
||||
+++ b/ipaserver/install/plugins/adtrust.py
|
||||
@@ -705,7 +705,8 @@ class update_tdo_to_new_layout(Updater):
|
||||
self.set_krb_principal([tgt_principal, nbt_principal],
|
||||
passwd_incoming,
|
||||
t_dn,
|
||||
- flags=self.KRB_PRINC_CREATE_DEFAULT)
|
||||
+ flags=self.KRB_PRINC_CREATE_DEFAULT
|
||||
+ | self.KRB_PRINC_CREATE_AGENT_PERMISSION)
|
||||
|
||||
# 3. INBOUND: krbtgt/<OUR REALM>@<REMOTE REALM> must exist
|
||||
trust_principal = self.tgt_principal_template.format(
|
||||
--
|
||||
2.47.1
|
||||
|
@ -1,72 +0,0 @@
|
||||
From f6645ebe5c0c0c030ec2e62e007d8dacd1b4e4cf Mon Sep 17 00:00:00 2001
|
||||
From: Erik Belko <ebelko@redhat.com>
|
||||
Date: Sep 03 2024 12:54:30 +0000
|
||||
Subject: ipatests: Update ipa-adtrust-install test
|
||||
|
||||
|
||||
update test_user_connects_smb_share_if_locked_specific_group with wait
|
||||
for SSSD to be online after ipa-adtrust-install command
|
||||
|
||||
Related: https://pagure.io/freeipa/issue/9655
|
||||
|
||||
Signed-off-by: Erik Belko <ebelko@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/ipatests/test_integration/test_adtrust_install.py b/ipatests/test_integration/test_adtrust_install.py
|
||||
index 72e8d87..de252db 100644
|
||||
--- a/ipatests/test_integration/test_adtrust_install.py
|
||||
+++ b/ipatests/test_integration/test_adtrust_install.py
|
||||
@@ -853,6 +853,8 @@ class TestIpaAdTrustInstall(IntegrationTest):
|
||||
self.master.config.admin_password,
|
||||
"-U"]
|
||||
)
|
||||
+ # Wait for SSSD to become online before doing any other check
|
||||
+ tasks.wait_for_sssd_domain_status_online(self.master)
|
||||
self.master.run_command(["mkdir", "/freeipa4234"])
|
||||
self.master.run_command(
|
||||
["chcon", "-t", "samba_share_t",
|
||||
|
||||
From 47920e78c81380c0a40986e55f05246aac132fbb Mon Sep 17 00:00:00 2001
|
||||
From: Erik Belko <ebelko@redhat.com>
|
||||
Date: May 21 2024 12:50:46 +0000
|
||||
Subject: ipatests: Update ipa-adtrust-install test
|
||||
|
||||
|
||||
update after change in implementation of `krb_utils.get_principal()` now using GSSAPI
|
||||
|
||||
Related: https://pagure.io/freeipa/issue/9575
|
||||
|
||||
Signed-off-by: Erik Belko <ebelko@redhat.com>
|
||||
Reviewed-By: Michal Polovka <mpolovka@redhat.com>
|
||||
|
||||
---
|
||||
|
||||
diff --git a/ipatests/test_integration/test_adtrust_install.py b/ipatests/test_integration/test_adtrust_install.py
|
||||
index 86d8d20..72e8d87 100644
|
||||
--- a/ipatests/test_integration/test_adtrust_install.py
|
||||
+++ b/ipatests/test_integration/test_adtrust_install.py
|
||||
@@ -464,18 +464,15 @@ class TestIpaAdTrustInstall(IntegrationTest):
|
||||
password
|
||||
"""
|
||||
password = "wrong_pwd"
|
||||
- msg = (
|
||||
- "Must have Kerberos credentials to setup AD trusts on server: "
|
||||
- "Major (458752): No credentials were supplied, or the credentials "
|
||||
- "were unavailable or inaccessible, Minor (2529639053): "
|
||||
- "No Kerberos credentials available (default cache: KCM:)\n"
|
||||
+ expected_substring = (
|
||||
+ "Must have Kerberos credentials to setup AD trusts on server:"
|
||||
)
|
||||
self.master.run_command(["kdestroy", "-A"])
|
||||
result = self.master.run_command(
|
||||
["ipa-adtrust-install", "-A", "admin", "-a",
|
||||
password, "-U"], raiseonerr=False
|
||||
)
|
||||
- assert msg in result.stderr_text
|
||||
+ assert expected_substring in result.stderr_text
|
||||
assert result.returncode != 0
|
||||
|
||||
def test_adtrust_install_with_invalid_rid_base_value(self):
|
||||
|
37
SOURCES/0037-Fix-the-typo-in-ipa_migrate_constants.patch
Normal file
37
SOURCES/0037-Fix-the-typo-in-ipa_migrate_constants.patch
Normal file
@ -0,0 +1,37 @@
|
||||
From 6a2310eda39b1341258211c7630ef4baf4555df5 Mon Sep 17 00:00:00 2001
|
||||
From: Sudhir Menon <sumenon@redhat.com>
|
||||
Date: Mon, 9 Dec 2024 23:03:56 +0530
|
||||
Subject: [PATCH] Fix the typo in ipa_migrate_constants.
|
||||
|
||||
ipa-migrate.log displays Privileges migrated as Privledges
|
||||
due to typo in labelling i.e 'label': 'Privledges'
|
||||
Hence changed that to 'label': 'Privileges'
|
||||
|
||||
---- LOG FILE ----
|
||||
INFO - Privledges: 3
|
||||
------------------
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9715
|
||||
|
||||
Signed-off-by: Sudhir Menon <sumenon@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
---
|
||||
ipaserver/install/ipa_migrate_constants.py | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ipaserver/install/ipa_migrate_constants.py b/ipaserver/install/ipa_migrate_constants.py
|
||||
index c140414ea6c607a93e35ef0705480d1002b7945e..e8192fb1aabae1c36669370eff242428a1f0355f 100644
|
||||
--- a/ipaserver/install/ipa_migrate_constants.py
|
||||
+++ b/ipaserver/install/ipa_migrate_constants.py
|
||||
@@ -886,7 +886,7 @@ DB_OBJECTS = {
|
||||
'pbac_priv': {
|
||||
'oc': ['groupofnames'],
|
||||
'subtree': ',cn=privileges,cn=pbac,$SUFFIX',
|
||||
- 'label': 'Privledges',
|
||||
+ 'label': 'Privileges',
|
||||
'mode': 'all',
|
||||
'count': 0,
|
||||
},
|
||||
--
|
||||
2.47.1
|
||||
|
@ -0,0 +1,35 @@
|
||||
From d8d4c5507bd3784d323e6836ff8456ba9608f115 Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Fri, 20 Sep 2024 09:36:41 +0200
|
||||
Subject: [PATCH] test_ipahealthcheck: skip connectivity_and_data check
|
||||
|
||||
PKI removed the clones.check connectivity_and_data check in
|
||||
11.5 and master branches. Skip the test depending on PKI version.
|
||||
The most recent version on 11.5 is 11.5.4 and still contains the check,
|
||||
hence skipping if version >= 11.5.5.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9668
|
||||
|
||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipatests/test_integration/test_ipahealthcheck.py | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py
|
||||
index a3e10b04487f0a12fdde19a8d1971a09f7d79b63..cc51a5a6a62fbc50927fc2fc51f129a069e70b69 100644
|
||||
--- a/ipatests/test_integration/test_ipahealthcheck.py
|
||||
+++ b/ipatests/test_integration/test_ipahealthcheck.py
|
||||
@@ -1219,6 +1219,9 @@ class TestIpaHealthCheck(IntegrationTest):
|
||||
This testcase checks that when ClonesConnectivyAndDataCheck
|
||||
is run it doesn't display source not found error
|
||||
"""
|
||||
+ if (tasks.get_pki_version(
|
||||
+ self.master) >= tasks.parse_version('11.5.5')):
|
||||
+ raise pytest.skip("PKI dropped ClonesConnectivyAndDataCheck")
|
||||
error_msg = (
|
||||
"Source 'pki.server.healthcheck.clones.connectivity_and_data' "
|
||||
"not found"
|
||||
--
|
||||
2.47.1
|
||||
|
36
SOURCES/0039-ipatests-Fixes-for-ipa-ipa-migration-tool.patch
Normal file
36
SOURCES/0039-ipatests-Fixes-for-ipa-ipa-migration-tool.patch
Normal file
@ -0,0 +1,36 @@
|
||||
From c294b7f6dbcae9c01d5366b19b3b070ffb730fa6 Mon Sep 17 00:00:00 2001
|
||||
From: Sudhir Menon <sumenon@redhat.com>
|
||||
Date: Wed, 11 Dec 2024 15:12:48 +0530
|
||||
Subject: [PATCH] ipatests: Fixes for ipa-ipa-migration tool
|
||||
|
||||
The test test_ipa_migrate_with_invalid_host has been
|
||||
failing in downstream run due to mismatch in the expected test output,
|
||||
hence the assert statement has been modified.
|
||||
|
||||
Related: https://pagure.io/freeipa/issue/3656
|
||||
|
||||
Signed-off-by: Sudhir Menon <sumenon@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
---
|
||||
ipatests/test_integration/test_ipa_ipa_migration.py | 4 +---
|
||||
1 file changed, 1 insertion(+), 3 deletions(-)
|
||||
|
||||
diff --git a/ipatests/test_integration/test_ipa_ipa_migration.py b/ipatests/test_integration/test_ipa_ipa_migration.py
|
||||
index 0c637a0141d95f34f951c60a9648adf8e87eaa63..95c29234fc7893d3eae5d900a58aa7b1162ed61d 100644
|
||||
--- a/ipatests/test_integration/test_ipa_ipa_migration.py
|
||||
+++ b/ipatests/test_integration/test_ipa_ipa_migration.py
|
||||
@@ -437,10 +437,8 @@ class TestIPAMigrateCLIOptions(MigrationTest):
|
||||
"""
|
||||
hostname = "server.invalid.host"
|
||||
ERR_MSG = (
|
||||
- "IPA to IPA migration starting ...\n"
|
||||
"Failed to bind to remote server: cannot connect to "
|
||||
- "'ldap://"
|
||||
- "{}': \n".format(hostname)
|
||||
+ "'ldap://{}':".format(hostname)
|
||||
)
|
||||
result = run_migrate(
|
||||
self.replicas[0],
|
||||
--
|
||||
2.47.1
|
||||
|
@ -0,0 +1,47 @@
|
||||
From ff5bb485d709ea02422cbafba51d23db384822af Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Fri, 20 Dec 2024 15:45:01 +0100
|
||||
Subject: [PATCH] Installation test: KRA on replica after cert renewal
|
||||
|
||||
Add a new test installing the KRA on a replica after the
|
||||
KRA certs have been renewed on the master.
|
||||
|
||||
Related: https://pagure.io/freeipa/issue/9692
|
||||
|
||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipatests/test_integration/test_installation.py | 10 +++++++++-
|
||||
1 file changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/ipatests/test_integration/test_installation.py b/ipatests/test_integration/test_installation.py
|
||||
index c5565c452010f23f038ddf329454b591ef09f6af..1fae472673a3934c86af2f9adc7b343c70e25b2b 100644
|
||||
--- a/ipatests/test_integration/test_installation.py
|
||||
+++ b/ipatests/test_integration/test_installation.py
|
||||
@@ -1322,7 +1322,7 @@ class TestInstallMaster(IntegrationTest):
|
||||
|
||||
class TestInstallMasterKRA(IntegrationTest):
|
||||
|
||||
- num_replicas = 0
|
||||
+ num_replicas = 1
|
||||
|
||||
@classmethod
|
||||
def install(cls, mh):
|
||||
@@ -1379,6 +1379,14 @@ class TestInstallMasterKRA(IntegrationTest):
|
||||
)
|
||||
assert starting_serial != int(cert.serial_number)
|
||||
|
||||
+ def test_install_replica_after_kracert_renewal(self):
|
||||
+ """
|
||||
+ Test replica installation with CA after the KRA certs renewal
|
||||
+ """
|
||||
+ tasks.install_replica(self.master, self.replicas[0],
|
||||
+ setup_ca=True)
|
||||
+ tasks.install_kra(self.replicas[0])
|
||||
+
|
||||
|
||||
class TestInstallMasterDNS(IntegrationTest):
|
||||
|
||||
--
|
||||
2.47.1
|
||||
|
@ -0,0 +1,45 @@
|
||||
From a707083b0987e6ffabb817fcc5e5138b4c755459 Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Fri, 20 Dec 2024 17:01:56 +0100
|
||||
Subject: [PATCH] KRA cert renewal: update ca.connector.KRA.transportCert
|
||||
|
||||
After the KRA transport cert has been renewed, the value
|
||||
of ca.connector.KRA.transportCert must also be updated in
|
||||
/etc/pki/pki-tomcat/ca/CS.cfg.
|
||||
Otherwise replica installation with KRA fails.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9692
|
||||
|
||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipaserver/install/cainstance.py | 13 ++++++++-----
|
||||
1 file changed, 8 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
|
||||
index 5c2c9f8b981cf5d587865f7680e2b231eae655e2..e03a8c863e14782679e19c6887f5e220131e4234 100644
|
||||
--- a/ipaserver/install/cainstance.py
|
||||
+++ b/ipaserver/install/cainstance.py
|
||||
@@ -1225,11 +1225,14 @@ class CAInstance(DogtagInstance):
|
||||
"""
|
||||
|
||||
# The cert directive to update per nickname
|
||||
- directives = {'auditSigningCert cert-pki-ca': 'ca.audit_signing.cert',
|
||||
- 'ocspSigningCert cert-pki-ca': 'ca.ocsp_signing.cert',
|
||||
- 'caSigningCert cert-pki-ca': 'ca.signing.cert',
|
||||
- 'subsystemCert cert-pki-ca': 'ca.subsystem.cert',
|
||||
- 'Server-Cert cert-pki-ca': 'ca.sslserver.cert'}
|
||||
+ directives = {
|
||||
+ 'auditSigningCert cert-pki-ca': 'ca.audit_signing.cert',
|
||||
+ 'ocspSigningCert cert-pki-ca': 'ca.ocsp_signing.cert',
|
||||
+ 'caSigningCert cert-pki-ca': 'ca.signing.cert',
|
||||
+ 'subsystemCert cert-pki-ca': 'ca.subsystem.cert',
|
||||
+ 'Server-Cert cert-pki-ca': 'ca.sslserver.cert',
|
||||
+ 'transportCert cert-pki-kra': 'ca.connector.KRA.transportCert'
|
||||
+ }
|
||||
|
||||
try:
|
||||
self.backup_config()
|
||||
--
|
||||
2.47.1
|
||||
|
@ -0,0 +1,45 @@
|
||||
From 2506d5de5a9dd8ebe6efc777c2eb76461f5b57e2 Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Mon, 6 Jan 2025 10:12:15 -0500
|
||||
Subject: [PATCH] Add 30-second timeout for certmonger request/start tracking
|
||||
|
||||
certmonger needs to validate that the PIN/password and/or token
|
||||
are valid and available. In the case of a very slow HSM this can
|
||||
take longer than the 5-second default timeout.
|
||||
|
||||
We saw an HSM that took 18 seconds to start tracking the CA signing
|
||||
certificate so default to 30 to be safe.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9725
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abbra@users.noreply.github.com>
|
||||
---
|
||||
ipalib/install/certmonger.py | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/ipalib/install/certmonger.py b/ipalib/install/certmonger.py
|
||||
index 7b22295152f752b6ab4de0f3525d48c541677aff..efc1ba4f42eab98df5fac51bafa3acc83ae91831 100644
|
||||
--- a/ipalib/install/certmonger.py
|
||||
+++ b/ipalib/install/certmonger.py
|
||||
@@ -477,7 +477,7 @@ def request_cert(
|
||||
request_parameters['cert-perms'] = perms[0]
|
||||
request_parameters['key-perms'] = perms[1]
|
||||
|
||||
- result = cm.obj_if.add_request(request_parameters)
|
||||
+ result = cm.obj_if.add_request(request_parameters, timeout=30)
|
||||
try:
|
||||
if result[0]:
|
||||
request = _cm_dbus_object(cm.bus, cm, result[1], DBUS_CM_REQUEST_IF,
|
||||
@@ -581,7 +581,7 @@ def start_tracking(
|
||||
if nss_user:
|
||||
params['nss-user'] = nss_user
|
||||
|
||||
- result = cm.obj_if.add_request(params)
|
||||
+ result = cm.obj_if.add_request(params, timeout=30)
|
||||
try:
|
||||
if result[0]:
|
||||
request = _cm_dbus_object(cm.bus, cm, result[1], DBUS_CM_REQUEST_IF,
|
||||
--
|
||||
2.47.1
|
||||
|
624
SOURCES/0043-Unify-use-of-option-parsers.patch
Normal file
624
SOURCES/0043-Unify-use-of-option-parsers.patch
Normal file
@ -0,0 +1,624 @@
|
||||
From d26ce5cccc211f83b3cce3fc5e548b5cb955bb81 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Fri, 13 Dec 2024 13:42:36 +0200
|
||||
Subject: [PATCH] Unify use of option parsers
|
||||
|
||||
Do not use direct optparse references, instead import IPAOptionParser
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
---
|
||||
install/tools/ipa-adtrust-install.in | 4 +---
|
||||
install/tools/ipa-managed-entries.in | 3 ++-
|
||||
ipaclient/install/ipa_client_automount.py | 4 ++--
|
||||
ipaclient/install/ipa_client_samba.py | 4 ++--
|
||||
ipalib/cli.py | 21 ++++++++++++---------
|
||||
ipalib/plugable.py | 8 ++++----
|
||||
ipapython/admintool.py | 3 +--
|
||||
ipapython/config.py | 18 +++++++++++-------
|
||||
ipapython/install/cli.py | 9 ++++-----
|
||||
ipaserver/install/ipa_acme_manage.py | 6 ++----
|
||||
ipaserver/install/ipa_backup.py | 5 ++---
|
||||
ipaserver/install/ipa_cacert_manage.py | 9 ++++-----
|
||||
ipaserver/install/ipa_kra_install.py | 5 ++---
|
||||
ipaserver/install/ipa_restore.py | 5 ++---
|
||||
ipaserver/install/ipa_server_certinstall.py | 7 +++----
|
||||
ipatests/i18n.py | 8 ++++----
|
||||
makeapi.in | 5 ++---
|
||||
17 files changed, 60 insertions(+), 64 deletions(-)
|
||||
|
||||
diff --git a/install/tools/ipa-adtrust-install.in b/install/tools/ipa-adtrust-install.in
|
||||
index cb2b78e504896b96cdc378fd879cc1f00c60904f..e7b0e369259da5d28d703558d9293ccfaf68f3ed 100644
|
||||
--- a/install/tools/ipa-adtrust-install.in
|
||||
+++ b/install/tools/ipa-adtrust-install.in
|
||||
@@ -29,8 +29,6 @@ import sys
|
||||
|
||||
import six
|
||||
|
||||
-from optparse import SUPPRESS_HELP # pylint: disable=deprecated-module
|
||||
-
|
||||
from ipalib.install import sysrestore
|
||||
from ipaserver.install import adtrust, service
|
||||
from ipaserver.install.installutils import (
|
||||
@@ -41,7 +39,7 @@ from ipapython.admintool import ScriptError
|
||||
from ipapython import version
|
||||
from ipapython import ipautil
|
||||
from ipalib import api, errors, krb_utils
|
||||
-from ipapython.config import IPAOptionParser
|
||||
+from ipapython.config import IPAOptionParser, SUPPRESS_HELP
|
||||
from ipaplatform.paths import paths
|
||||
from ipapython.ipa_log_manager import standard_logging_setup
|
||||
|
||||
diff --git a/install/tools/ipa-managed-entries.in b/install/tools/ipa-managed-entries.in
|
||||
index e9be41b7a34ed62e65ab40bf544a6e4cea7c598a..e3f121943eb3b18ca8f7f8bfeae7813cbc9bd753 100644
|
||||
--- a/install/tools/ipa-managed-entries.in
|
||||
+++ b/install/tools/ipa-managed-entries.in
|
||||
@@ -39,7 +39,8 @@ logger = logging.getLogger(os.path.basename(__file__))
|
||||
def parse_options():
|
||||
usage = "%prog [options] <status|enable|disable>\n"
|
||||
usage += "%prog [options]\n"
|
||||
- parser = OptionParser(usage=usage, formatter=config.IPAFormatter())
|
||||
+ parser = config.IPAOptionParser(usage=usage,
|
||||
+ formatter=config.IPAFormatter())
|
||||
|
||||
parser.add_option("-d", "--debug", action="store_true", dest="debug",
|
||||
help="Display debugging information about the update(s)")
|
||||
diff --git a/ipaclient/install/ipa_client_automount.py b/ipaclient/install/ipa_client_automount.py
|
||||
index 4439932bd723c40c429dac2c08e97d326e414d24..9f49ff9edeee2648d2be1dea6b09806ba0b5e041 100644
|
||||
--- a/ipaclient/install/ipa_client_automount.py
|
||||
+++ b/ipaclient/install/ipa_client_automount.py
|
||||
@@ -34,7 +34,6 @@ import SSSDConfig
|
||||
|
||||
from six.moves.urllib.parse import urlsplit
|
||||
|
||||
-from optparse import OptionParser # pylint: disable=deprecated-module
|
||||
from ipapython import ipachangeconf
|
||||
from ipaclient import discovery
|
||||
from ipaclient.install.client import (
|
||||
@@ -52,6 +51,7 @@ from ipaplatform.tasks import tasks
|
||||
from ipaplatform import services
|
||||
from ipaplatform.paths import paths
|
||||
from ipapython.admintool import ScriptError
|
||||
+from ipapython.config import IPAOptionParser
|
||||
|
||||
|
||||
logger = logging.getLogger(os.path.basename(__file__))
|
||||
@@ -59,7 +59,7 @@ logger = logging.getLogger(os.path.basename(__file__))
|
||||
|
||||
def parse_options():
|
||||
usage = "%prog [options]\n"
|
||||
- parser = OptionParser(usage=usage)
|
||||
+ parser = IPAOptionParser(usage=usage)
|
||||
parser.add_option("--server", dest="server", help="FQDN of IPA server")
|
||||
parser.add_option(
|
||||
"--location",
|
||||
diff --git a/ipaclient/install/ipa_client_samba.py b/ipaclient/install/ipa_client_samba.py
|
||||
index 81d670c34cae0f91a436a2a2d1e0d525057b6cc7..5c33abb4cabe47ff311b7d769fefa37991f7d453 100755
|
||||
--- a/ipaclient/install/ipa_client_samba.py
|
||||
+++ b/ipaclient/install/ipa_client_samba.py
|
||||
@@ -9,7 +9,6 @@ import logging
|
||||
import os
|
||||
import gssapi
|
||||
from urllib.parse import urlsplit
|
||||
-from optparse import OptionParser # pylint: disable=deprecated-module
|
||||
from contextlib import contextmanager
|
||||
|
||||
from ipaclient import discovery
|
||||
@@ -31,6 +30,7 @@ from ipaplatform.constants import constants
|
||||
from ipaplatform import services
|
||||
from ipapython.admintool import ScriptError
|
||||
from samba import generate_random_password
|
||||
+from ipapython.config import IPAOptionParser
|
||||
|
||||
logger = logging.getLogger(os.path.basename(__file__))
|
||||
logger.setLevel(logging.DEBUG)
|
||||
@@ -68,7 +68,7 @@ def use_api_as_principal(principal, keytab):
|
||||
|
||||
def parse_options():
|
||||
usage = "%prog [options]\n"
|
||||
- parser = OptionParser(usage=usage)
|
||||
+ parser = IPAOptionParser(usage=usage)
|
||||
parser.add_option(
|
||||
"--server",
|
||||
dest="server",
|
||||
diff --git a/ipalib/cli.py b/ipalib/cli.py
|
||||
index d9c2ac16513101098c8f9a2258ae930b3b2cebf0..667b213fd4e4706e6eecd4d2b4737fb3fede4c93 100644
|
||||
--- a/ipalib/cli.py
|
||||
+++ b/ipalib/cli.py
|
||||
@@ -30,7 +30,6 @@ import textwrap
|
||||
import sys
|
||||
import getpass
|
||||
import code
|
||||
-import optparse # pylint: disable=deprecated-module
|
||||
import os
|
||||
import pprint
|
||||
import fcntl
|
||||
@@ -71,6 +70,8 @@ from ipalib.text import _
|
||||
from ipalib import api
|
||||
from ipapython.dnsutil import DNSName
|
||||
from ipapython.admintool import ScriptError
|
||||
+from ipapython.config import (IPAOptionParser, IPAFormatter,
|
||||
+ OptionGroup, make_option)
|
||||
|
||||
import datetime
|
||||
|
||||
@@ -1121,7 +1122,8 @@ class Collector:
|
||||
def __todict__(self):
|
||||
return dict(self.__options)
|
||||
|
||||
-class CLIOptionParserFormatter(optparse.IndentedHelpFormatter):
|
||||
+
|
||||
+class CLIOptionParserFormatter(IPAFormatter):
|
||||
def format_argument(self, name, help_string):
|
||||
result = []
|
||||
opt_width = self.help_position - self.current_indent - 2
|
||||
@@ -1141,7 +1143,8 @@ class CLIOptionParserFormatter(optparse.IndentedHelpFormatter):
|
||||
result.append("\n")
|
||||
return "".join(result)
|
||||
|
||||
-class CLIOptionParser(optparse.OptionParser):
|
||||
+
|
||||
+class CLIOptionParser(IPAOptionParser):
|
||||
"""
|
||||
This OptionParser subclass adds an ability to print positional
|
||||
arguments in CLI help. Custom formatter is used to format the argument
|
||||
@@ -1151,13 +1154,13 @@ class CLIOptionParser(optparse.OptionParser):
|
||||
self._arguments = []
|
||||
if 'formatter' not in kwargs:
|
||||
kwargs['formatter'] = CLIOptionParserFormatter()
|
||||
- optparse.OptionParser.__init__(self, *args, **kwargs)
|
||||
+ IPAOptionParser.__init__(self, *args, **kwargs)
|
||||
|
||||
def format_option_help(self, formatter=None):
|
||||
"""
|
||||
Prepend argument help to standard OptionParser's option help
|
||||
"""
|
||||
- option_help = optparse.OptionParser.format_option_help(self, formatter)
|
||||
+ option_help = IPAOptionParser.format_option_help(self, formatter)
|
||||
|
||||
if isinstance(formatter, CLIOptionParserFormatter):
|
||||
heading = unicode(_("Positional arguments"))
|
||||
@@ -1272,7 +1275,7 @@ class cli(backend.Executioner):
|
||||
"""Get or create an option group for the given name"""
|
||||
option_group = option_groups.get(group_name)
|
||||
if option_group is None:
|
||||
- option_group = optparse.OptionGroup(parser, group_name)
|
||||
+ option_group = OptionGroup(parser, group_name)
|
||||
parser.add_option_group(option_group)
|
||||
option_groups[group_name] = option_group
|
||||
return option_group
|
||||
@@ -1298,7 +1301,7 @@ class cli(backend.Executioner):
|
||||
option_names = ['--%s' % cli_name]
|
||||
if option.cli_short_name:
|
||||
option_names.append('-%s' % option.cli_short_name)
|
||||
- opt = optparse.make_option(*option_names, **kw)
|
||||
+ opt = make_option(*option_names, **kw)
|
||||
if option.option_group is None:
|
||||
parser.add_option(opt)
|
||||
else:
|
||||
@@ -1312,7 +1315,7 @@ class cli(backend.Executioner):
|
||||
group = _get_option_group(unicode(_('Deprecated options')))
|
||||
for alias in option.deprecated_cli_aliases:
|
||||
name = '--%s' % alias
|
||||
- group.add_option(optparse.make_option(name, **new_kw))
|
||||
+ group.add_option(make_option(name, **new_kw))
|
||||
|
||||
for arg in cmd.args():
|
||||
name = self.__get_arg_name(arg, format_name=False)
|
||||
@@ -1442,7 +1445,7 @@ class cli(backend.Executioner):
|
||||
)
|
||||
|
||||
|
||||
-class IPAHelpFormatter(optparse.IndentedHelpFormatter):
|
||||
+class IPAHelpFormatter(IPAFormatter):
|
||||
"""Formatter suitable for printing IPA command help
|
||||
|
||||
The default help formatter reflows text to fit the terminal, but it
|
||||
diff --git a/ipalib/plugable.py b/ipalib/plugable.py
|
||||
index 2e2861df054fa7ed3533d0f82a23b65322ab591b..a87e6e8914fa5579920aad8190c7f6a86cb3dfea 100644
|
||||
--- a/ipalib/plugable.py
|
||||
+++ b/ipalib/plugable.py
|
||||
@@ -33,7 +33,6 @@ import sys
|
||||
import threading
|
||||
import os
|
||||
from os import path
|
||||
-import optparse # pylint: disable=deprecated-module
|
||||
import textwrap
|
||||
import collections
|
||||
import importlib
|
||||
@@ -47,6 +46,7 @@ from ipalib.util import classproperty
|
||||
from ipalib.base import ReadOnly, lock, islocked
|
||||
from ipalib.constants import DEFAULT_CONFIG
|
||||
from ipapython import ipa_log_manager, ipautil
|
||||
+from ipapython.config import IPAOptionParser, IPAFormatter
|
||||
from ipapython.ipa_log_manager import (
|
||||
LOGGING_FORMAT_FILE,
|
||||
LOGGING_FORMAT_STDERR)
|
||||
@@ -526,7 +526,7 @@ class API(ReadOnly):
|
||||
|
||||
def build_global_parser(self, parser=None, context=None):
|
||||
"""
|
||||
- Add global options to an optparse.OptionParser instance.
|
||||
+ Add global options to an IPAOptionParser instance.
|
||||
"""
|
||||
def config_file_callback(option, opt, value, parser):
|
||||
if not os.path.isfile(value):
|
||||
@@ -536,7 +536,7 @@ class API(ReadOnly):
|
||||
parser.values.conf = value
|
||||
|
||||
if parser is None:
|
||||
- parser = optparse.OptionParser(
|
||||
+ parser = IPAOptionParser(
|
||||
add_help_option=False,
|
||||
formatter=IPAHelpFormatter(),
|
||||
usage='%prog [global-options] COMMAND [command-options]',
|
||||
@@ -821,7 +821,7 @@ class API(ReadOnly):
|
||||
return self.__next[plugin]
|
||||
|
||||
|
||||
-class IPAHelpFormatter(optparse.IndentedHelpFormatter):
|
||||
+class IPAHelpFormatter(IPAFormatter):
|
||||
def format_epilog(self, epilog):
|
||||
text_width = self.width - self.current_indent
|
||||
indent = " " * self.current_indent
|
||||
diff --git a/ipapython/admintool.py b/ipapython/admintool.py
|
||||
index fdb4400d879165612405b3ba159a220773bd8d69..dff9112eba4009d2fc1a6202756c6671ba4d909d 100644
|
||||
--- a/ipapython/admintool.py
|
||||
+++ b/ipapython/admintool.py
|
||||
@@ -26,7 +26,6 @@ import logging
|
||||
import sys
|
||||
import os
|
||||
import traceback
|
||||
-from optparse import OptionGroup # pylint: disable=deprecated-module
|
||||
|
||||
from ipaplatform.osinfo import osinfo
|
||||
from ipapython import version
|
||||
@@ -113,7 +112,7 @@ class AdminTool:
|
||||
:param parser: The parser to add options to
|
||||
:param debug_option: Add a --debug option as an alias to --verbose
|
||||
"""
|
||||
- group = OptionGroup(parser, "Logging and output options")
|
||||
+ group = config.OptionGroup(parser, "Logging and output options")
|
||||
group.add_option("-v", "--verbose", dest="verbose", default=False,
|
||||
action="store_true", help="print debugging information")
|
||||
if debug_option:
|
||||
diff --git a/ipapython/config.py b/ipapython/config.py
|
||||
index f53d0f998aaedf47715764577dd7f5048f4ca841..7af4dfdeb0047586de9694f233be8bf543190b9c 100644
|
||||
--- a/ipapython/config.py
|
||||
+++ b/ipapython/config.py
|
||||
@@ -18,9 +18,9 @@
|
||||
#
|
||||
from __future__ import absolute_import
|
||||
|
||||
-# pylint: disable=deprecated-module
|
||||
-from optparse import (
|
||||
- Option, Values, OptionParser, IndentedHelpFormatter, OptionValueError)
|
||||
+# pylint: disable=deprecated-module, disable=unused-import
|
||||
+from optparse import (Option, Values, OptionGroup, OptionParser, SUPPRESS_HELP,
|
||||
+ IndentedHelpFormatter, OptionValueError, make_option)
|
||||
# pylint: enable=deprecated-module
|
||||
from copy import copy
|
||||
from configparser import ConfigParser as SafeConfigParser
|
||||
@@ -113,10 +113,14 @@ class IPAOptionParser(OptionParser):
|
||||
description=None,
|
||||
formatter=None,
|
||||
add_help_option=True,
|
||||
- prog=None):
|
||||
- OptionParser.__init__(self, usage, option_list, option_class,
|
||||
- version, conflict_handler, description,
|
||||
- formatter, add_help_option, prog)
|
||||
+ prog=None,
|
||||
+ epilog=None):
|
||||
+ OptionParser.__init__(self, usage=usage, option_list=option_list,
|
||||
+ option_class=option_class, version=version,
|
||||
+ conflict_handler=conflict_handler,
|
||||
+ description=description, formatter=formatter,
|
||||
+ add_help_option=add_help_option, prog=prog,
|
||||
+ epilog=epilog)
|
||||
|
||||
def get_safe_opts(self, opts):
|
||||
"""
|
||||
diff --git a/ipapython/install/cli.py b/ipapython/install/cli.py
|
||||
index ab212be4e2c3f9c2aae97f7759672ef7c68c3347..a048b3c7c64bc22338e4517d64b33a44446c58a3 100644
|
||||
--- a/ipapython/install/cli.py
|
||||
+++ b/ipapython/install/cli.py
|
||||
@@ -9,12 +9,11 @@ Command line support.
|
||||
import collections
|
||||
import enum
|
||||
import logging
|
||||
-import optparse # pylint: disable=deprecated-module
|
||||
import signal
|
||||
|
||||
import six
|
||||
|
||||
-from ipapython import admintool
|
||||
+from ipapython import admintool, config
|
||||
from ipapython.ipa_log_manager import standard_logging_setup
|
||||
from ipapython.ipautil import (CheckedIPAddress, CheckedIPAddressLoopback,
|
||||
private_ccache)
|
||||
@@ -158,7 +157,7 @@ class ConfigureTool(admintool.AdminTool):
|
||||
try:
|
||||
opt_group = groups[group_cls]
|
||||
except KeyError:
|
||||
- opt_group = groups[group_cls] = optparse.OptionGroup(
|
||||
+ opt_group = groups[group_cls] = config.OptionGroup(
|
||||
parser, "{0} options".format(group_cls.description))
|
||||
parser.add_option_group(opt_group)
|
||||
|
||||
@@ -232,7 +231,7 @@ class ConfigureTool(admintool.AdminTool):
|
||||
if not hidden:
|
||||
help = knob_cls.description
|
||||
else:
|
||||
- help = optparse.SUPPRESS_HELP
|
||||
+ help = config.SUPPRESS_HELP
|
||||
|
||||
opt_group.add_option(
|
||||
*opt_strs,
|
||||
@@ -256,7 +255,7 @@ class ConfigureTool(admintool.AdminTool):
|
||||
|
||||
# fake option parser to parse positional arguments
|
||||
# (because optparse does not support positional argument parsing)
|
||||
- fake_option_parser = optparse.OptionParser()
|
||||
+ fake_option_parser = config.IPAOptionParser()
|
||||
self.add_options(fake_option_parser, True)
|
||||
|
||||
fake_option_map = {option.dest: option
|
||||
diff --git a/ipaserver/install/ipa_acme_manage.py b/ipaserver/install/ipa_acme_manage.py
|
||||
index dc2359f49dfdd5c8f44ab96ee11a7240f8937e11..0decab394c1c18067fe0c194c040805a8d93d42d 100644
|
||||
--- a/ipaserver/install/ipa_acme_manage.py
|
||||
+++ b/ipaserver/install/ipa_acme_manage.py
|
||||
@@ -7,14 +7,12 @@ import enum
|
||||
import pki.util
|
||||
import logging
|
||||
|
||||
-from optparse import OptionGroup # pylint: disable=deprecated-module
|
||||
-
|
||||
from ipalib import api, errors, x509
|
||||
from ipalib import _
|
||||
from ipalib.facts import is_ipa_configured
|
||||
from ipaplatform.paths import paths
|
||||
from ipapython.admintool import AdminTool
|
||||
-from ipapython import cookie, dogtag
|
||||
+from ipapython import cookie, dogtag, config
|
||||
from ipapython.ipautil import run
|
||||
from ipapython.certdb import NSSDatabase, EXTERNAL_CA_TRUST_FLAGS
|
||||
from ipaserver.install import cainstance
|
||||
@@ -143,7 +141,7 @@ class IPAACMEManage(AdminTool):
|
||||
@classmethod
|
||||
def add_options(cls, parser):
|
||||
|
||||
- group = OptionGroup(parser, 'Pruning')
|
||||
+ group = config.OptionGroup(parser, 'Pruning')
|
||||
group.add_option(
|
||||
"--enable", dest="enable", action="store_true",
|
||||
default=False, help="Enable certificate pruning")
|
||||
diff --git a/ipaserver/install/ipa_backup.py b/ipaserver/install/ipa_backup.py
|
||||
index 982e5dfc4c0339aada88f936ab450b7fc16944f2..b6af63813fc4eaadab44ad95386d86ae4f1e21ee 100644
|
||||
--- a/ipaserver/install/ipa_backup.py
|
||||
+++ b/ipaserver/install/ipa_backup.py
|
||||
@@ -20,7 +20,6 @@
|
||||
from __future__ import absolute_import, print_function
|
||||
|
||||
import logging
|
||||
-import optparse # pylint: disable=deprecated-module
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
@@ -32,7 +31,7 @@ import six
|
||||
from ipaplatform.paths import paths
|
||||
from ipaplatform import services
|
||||
from ipalib import api, errors
|
||||
-from ipapython import version
|
||||
+from ipapython import version, config
|
||||
from ipapython.ipautil import run, write_tmp_file
|
||||
from ipapython import admintool, certdb
|
||||
from ipapython.dn import DN
|
||||
@@ -245,7 +244,7 @@ class Backup(admintool.AdminTool):
|
||||
|
||||
parser.add_option(
|
||||
"--gpg-keyring", dest="gpg_keyring",
|
||||
- help=optparse.SUPPRESS_HELP)
|
||||
+ help=config.SUPPRESS_HELP)
|
||||
parser.add_option(
|
||||
"--gpg", dest="gpg", action="store_true",
|
||||
default=False, help="Encrypt the backup")
|
||||
diff --git a/ipaserver/install/ipa_cacert_manage.py b/ipaserver/install/ipa_cacert_manage.py
|
||||
index f6ab736fa985b00ba66a7001c4c4e2188841bcbe..048245237855212afe1f3ec4795b2253026ef864 100644
|
||||
--- a/ipaserver/install/ipa_cacert_manage.py
|
||||
+++ b/ipaserver/install/ipa_cacert_manage.py
|
||||
@@ -22,14 +22,13 @@ from __future__ import print_function, absolute_import
|
||||
import datetime
|
||||
import logging
|
||||
import os
|
||||
-from optparse import OptionGroup # pylint: disable=deprecated-module
|
||||
import gssapi
|
||||
|
||||
from ipalib.constants import (
|
||||
RENEWAL_CA_NAME, RENEWAL_REUSE_CA_NAME, RENEWAL_SELFSIGNED_CA_NAME,
|
||||
IPA_CA_CN)
|
||||
from ipalib.install import certmonger, certstore
|
||||
-from ipapython import admintool, ipautil
|
||||
+from ipapython import admintool, ipautil, config
|
||||
from ipapython.certdb import (EMPTY_TRUST_FLAGS,
|
||||
EXTERNAL_CA_TRUST_FLAGS,
|
||||
TrustFlags,
|
||||
@@ -61,7 +60,7 @@ class CACertManage(admintool.AdminTool):
|
||||
"-p", "--password", dest='password',
|
||||
help="Directory Manager password")
|
||||
|
||||
- renew_group = OptionGroup(parser, "Renew options")
|
||||
+ renew_group = config.OptionGroup(parser, "Renew options")
|
||||
renew_group.add_option(
|
||||
"--self-signed", dest='self_signed',
|
||||
action='store_true',
|
||||
@@ -89,7 +88,7 @@ class CACertManage(admintool.AdminTool):
|
||||
"certificate chain")
|
||||
parser.add_option_group(renew_group)
|
||||
|
||||
- install_group = OptionGroup(parser, "Install options")
|
||||
+ install_group = config.OptionGroup(parser, "Install options")
|
||||
install_group.add_option(
|
||||
"-n", "--nickname", dest='nickname',
|
||||
help="Nickname for the certificate")
|
||||
@@ -98,7 +97,7 @@ class CACertManage(admintool.AdminTool):
|
||||
help="Trust flags for the certificate in certutil format")
|
||||
parser.add_option_group(install_group)
|
||||
|
||||
- delete_group = OptionGroup(parser, "Delete options")
|
||||
+ delete_group = config.OptionGroup(parser, "Delete options")
|
||||
delete_group.add_option(
|
||||
"-f", "--force", action='store_true',
|
||||
help="Force removing the CA even if chain validation fails")
|
||||
diff --git a/ipaserver/install/ipa_kra_install.py b/ipaserver/install/ipa_kra_install.py
|
||||
index 3e4cd67fa677db2534a639eb6beb14dfd78bf035..8a09179f7fa0c2ddad72d01e9c3eaf98575d0a88 100644
|
||||
--- a/ipaserver/install/ipa_kra_install.py
|
||||
+++ b/ipaserver/install/ipa_kra_install.py
|
||||
@@ -22,13 +22,12 @@ from __future__ import print_function, absolute_import
|
||||
import logging
|
||||
import sys
|
||||
import tempfile
|
||||
-from optparse import SUPPRESS_HELP # pylint: disable=deprecated-module
|
||||
|
||||
from textwrap import dedent
|
||||
from ipalib import api
|
||||
from ipalib.constants import DOMAIN_LEVEL_1
|
||||
from ipaplatform.paths import paths
|
||||
-from ipapython import admintool
|
||||
+from ipapython import admintool, config
|
||||
from ipaserver.install import service
|
||||
from ipaserver.install import cainstance
|
||||
from ipaserver.install import custodiainstance
|
||||
@@ -73,7 +72,7 @@ class KRAInstall(admintool.AdminTool):
|
||||
parser.add_option(
|
||||
"--uninstall",
|
||||
dest="uninstall", action="store_true", default=False,
|
||||
- help=SUPPRESS_HELP)
|
||||
+ help=config.SUPPRESS_HELP)
|
||||
|
||||
parser.add_option(
|
||||
"--pki-config-override", dest="pki_config_override",
|
||||
diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py
|
||||
index 57ad8dd05206132d3458fa84e7fb996b135f7f71..8d75a0e6beba09086bc2ce8c73f3bcfe81e52113 100644
|
||||
--- a/ipaserver/install/ipa_restore.py
|
||||
+++ b/ipaserver/install/ipa_restore.py
|
||||
@@ -20,7 +20,6 @@
|
||||
from __future__ import absolute_import, print_function
|
||||
|
||||
import logging
|
||||
-import optparse # pylint: disable=deprecated-module
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
@@ -34,7 +33,7 @@ import six
|
||||
from ipaclient.install.client import update_ipa_nssdb
|
||||
from ipalib import api, errors
|
||||
from ipalib.constants import FQDN
|
||||
-from ipapython import version, ipautil
|
||||
+from ipapython import version, ipautil, config
|
||||
from ipapython.ipautil import run, user_input
|
||||
from ipapython import admintool, certdb
|
||||
from ipapython.dn import DN
|
||||
@@ -190,7 +189,7 @@ class Restore(admintool.AdminTool):
|
||||
help="Directory Manager password")
|
||||
parser.add_option(
|
||||
"--gpg-keyring", dest="gpg_keyring",
|
||||
- help=optparse.SUPPRESS_HELP)
|
||||
+ help=config.SUPPRESS_HELP)
|
||||
parser.add_option(
|
||||
"--data", dest="data_only", action="store_true",
|
||||
default=False, help="Restore only the data")
|
||||
diff --git a/ipaserver/install/ipa_server_certinstall.py b/ipaserver/install/ipa_server_certinstall.py
|
||||
index e29f00ec37779aeb10255c5df6e10d6ecc0a6d11..e9f680b1d1e505f89fc1611b8dbb3f84768f6781 100644
|
||||
--- a/ipaserver/install/ipa_server_certinstall.py
|
||||
+++ b/ipaserver/install/ipa_server_certinstall.py
|
||||
@@ -22,12 +22,11 @@ from __future__ import print_function, absolute_import
|
||||
import os
|
||||
import os.path
|
||||
import tempfile
|
||||
-import optparse # pylint: disable=deprecated-module
|
||||
|
||||
from ipalib import x509
|
||||
from ipalib.install import certmonger
|
||||
from ipaplatform.paths import paths
|
||||
-from ipapython import admintool, dogtag
|
||||
+from ipapython import admintool, dogtag, config
|
||||
from ipapython.certdb import NSSDatabase, get_ca_nickname
|
||||
from ipapython.dn import DN
|
||||
from ipapython import ipaldap
|
||||
@@ -65,8 +64,8 @@ class ServerCertInstall(admintool.AdminTool):
|
||||
help="The password of the PKCS#12 file")
|
||||
parser.add_option(
|
||||
"--dirsrv_pin", "--http_pin",
|
||||
- dest="pin",
|
||||
- help=optparse.SUPPRESS_HELP)
|
||||
+ dest="pin", sensitive=True,
|
||||
+ help=config.SUPPRESS_HELP)
|
||||
parser.add_option(
|
||||
"--cert-name",
|
||||
dest="cert_name", metavar="NAME",
|
||||
diff --git a/ipatests/i18n.py b/ipatests/i18n.py
|
||||
index 49f5c4c3232346db3147bd7a5ba8056344ac907f..57915c286be72124fa23380f97f3922496f00c22 100644
|
||||
--- a/ipatests/i18n.py
|
||||
+++ b/ipatests/i18n.py
|
||||
@@ -22,7 +22,6 @@ from __future__ import print_function
|
||||
|
||||
# WARNING: Do not import ipa modules, this is also used as a
|
||||
# stand-alone script (invoked from po Makefile).
|
||||
-import optparse # pylint: disable=deprecated-module
|
||||
import sys
|
||||
import gettext
|
||||
import re
|
||||
@@ -30,6 +29,7 @@ import os
|
||||
import traceback
|
||||
import polib
|
||||
from collections import namedtuple
|
||||
+from ipapython import config
|
||||
|
||||
import six
|
||||
|
||||
@@ -722,9 +722,9 @@ usage ='''
|
||||
def main():
|
||||
global verbose, print_traceback, pedantic, show_strings
|
||||
|
||||
- parser = optparse.OptionParser(usage=usage)
|
||||
+ parser = config.IPAOptionParser(usage=usage)
|
||||
|
||||
- mode_group = optparse.OptionGroup(parser, 'Operational Mode',
|
||||
+ mode_group = config.OptionGroup(parser, 'Operational Mode',
|
||||
'You must select one these modes to run in')
|
||||
|
||||
mode_group.add_option('-g', '--test-gettext', action='store_const', const='test_gettext', dest='mode',
|
||||
@@ -748,7 +748,7 @@ def main():
|
||||
parser.add_option('--traceback', action='store_true', dest='print_traceback', default=False,
|
||||
help='print the traceback when an exception occurs')
|
||||
|
||||
- param_group = optparse.OptionGroup(parser, 'Run Time Parameters',
|
||||
+ param_group = config.OptionGroup(parser, 'Run Time Parameters',
|
||||
'These may be used to modify the run time defaults')
|
||||
|
||||
param_group.add_option('--test-lang', action='store', dest='test_lang', default='test',
|
||||
diff --git a/makeapi.in b/makeapi.in
|
||||
index a801b9253db9500e0510fe591074ccf2e6d752c1..8fc87d23de743a6d661112ee616dce129a785a36 100644
|
||||
--- a/makeapi.in
|
||||
+++ b/makeapi.in
|
||||
@@ -38,6 +38,7 @@ from ipalib.parameters import Param
|
||||
from ipalib.output import Output
|
||||
from ipalib.text import Gettext, NGettext, ConcatenatedLazyText
|
||||
from ipalib.capabilities import capabilities
|
||||
+from ipapython import config
|
||||
|
||||
API_FILE='API.txt'
|
||||
|
||||
@@ -84,9 +85,7 @@ OUTPUT_IGNORED_ATTRIBUTES = (
|
||||
)
|
||||
|
||||
def parse_options():
|
||||
- from optparse import OptionParser # pylint: disable=deprecated-module
|
||||
-
|
||||
- parser = OptionParser()
|
||||
+ parser = config.IPAOptionParser()
|
||||
parser.add_option("--validate", dest="validate", action="store_true",
|
||||
default=False, help="Validate the API vs the stored API")
|
||||
|
||||
--
|
||||
2.47.1
|
||||
|
@ -0,0 +1,422 @@
|
||||
From f9314562aaae03619eb89ae762bc24182174ad28 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Fri, 8 Nov 2024 14:59:20 +0200
|
||||
Subject: [PATCH] ipa tools: remove sensitive material from the commandline
|
||||
|
||||
When command line tools accept passwords, remove them from the command
|
||||
line so that they don't get visible in '/proc/pid/commandline'.
|
||||
|
||||
There is no common method to access the original ARGV vector and modify
|
||||
it from Python. Since this mostly affects Linux systems where IPA
|
||||
services run, we expect use of GNU libc and thus can rely on internal
|
||||
glibc symbols. If they aren't available, the code will skip removing
|
||||
passwords.
|
||||
|
||||
Fixes: CVE-2024-11029
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
---
|
||||
.../com.redhat.idm.trust-fetch-domains.in | 5 ++-
|
||||
install/tools/ipa-adtrust-install.in | 3 +-
|
||||
install/tools/ipa-ca-install.in | 2 +
|
||||
install/tools/ipa-compat-manage.in | 6 ++-
|
||||
install/tools/ipa-csreplica-manage.in | 12 +++---
|
||||
install/tools/ipa-managed-entries.in | 5 ++-
|
||||
install/tools/ipa-replica-conncheck.in | 7 ++--
|
||||
install/tools/ipa-replica-manage.in | 10 +++--
|
||||
ipapython/admintool.py | 40 +++++++++++++++++++
|
||||
ipaserver/install/ipa_migrate.py | 17 +++++++-
|
||||
ipaserver/install/ipa_restore.py | 2 +-
|
||||
ipaserver/install/ipa_server_certinstall.py | 2 +-
|
||||
12 files changed, 90 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/install/oddjob/com.redhat.idm.trust-fetch-domains.in b/install/oddjob/com.redhat.idm.trust-fetch-domains.in
|
||||
index 45c1f1463d5849d753c2913aa0b86b845cfce784..b86be0212c462e82d9379f55d5d3198c1017d2e7 100644
|
||||
--- a/install/oddjob/com.redhat.idm.trust-fetch-domains.in
|
||||
+++ b/install/oddjob/com.redhat.idm.trust-fetch-domains.in
|
||||
@@ -15,6 +15,7 @@ import six
|
||||
import gssapi
|
||||
|
||||
from ipalib.install.kinit import kinit_keytab, kinit_password
|
||||
+from ipapython.admintool import admin_cleanup_global_argv
|
||||
|
||||
if six.PY3:
|
||||
unicode = str
|
||||
@@ -52,11 +53,13 @@ def parse_options():
|
||||
"--password",
|
||||
action="store",
|
||||
dest="password",
|
||||
- help="Display debugging information",
|
||||
+ help="Password for Active Directory administrator",
|
||||
+ sensitive=True
|
||||
)
|
||||
|
||||
options, args = parser.parse_args()
|
||||
safe_options = parser.get_safe_opts(options)
|
||||
+ admin_cleanup_global_argv(parser, options, sys.argv)
|
||||
|
||||
# We only use first argument of the passed args but as D-BUS interface
|
||||
# in oddjobd cannot expose optional, we fill in empty slots from IPA side
|
||||
diff --git a/install/tools/ipa-adtrust-install.in b/install/tools/ipa-adtrust-install.in
|
||||
index e7b0e369259da5d28d703558d9293ccfaf68f3ed..1efccdb678d17410667b1721670bf6bf79152109 100644
|
||||
--- a/install/tools/ipa-adtrust-install.in
|
||||
+++ b/install/tools/ipa-adtrust-install.in
|
||||
@@ -35,7 +35,7 @@ from ipaserver.install.installutils import (
|
||||
read_password,
|
||||
check_server_configuration,
|
||||
run_script)
|
||||
-from ipapython.admintool import ScriptError
|
||||
+from ipapython.admintool import ScriptError, admin_cleanup_global_argv
|
||||
from ipapython import version
|
||||
from ipapython import ipautil
|
||||
from ipalib import api, errors, krb_utils
|
||||
@@ -93,6 +93,7 @@ def parse_options():
|
||||
|
||||
options, _args = parser.parse_args()
|
||||
safe_options = parser.get_safe_opts(options)
|
||||
+ admin_cleanup_global_argv(parser, options, sys.argv)
|
||||
|
||||
return safe_options, options
|
||||
|
||||
diff --git a/install/tools/ipa-ca-install.in b/install/tools/ipa-ca-install.in
|
||||
index 9f3d16669679a245b73e044622ff52321524fcde..b437e761f760ab715c27bc330ac0f2e66e72ef5b 100644
|
||||
--- a/install/tools/ipa-ca-install.in
|
||||
+++ b/install/tools/ipa-ca-install.in
|
||||
@@ -42,6 +42,7 @@ from ipalib.constants import DOMAIN_LEVEL_1
|
||||
from ipapython.config import IPAOptionParser
|
||||
from ipapython.ipa_log_manager import standard_logging_setup
|
||||
from ipaplatform.paths import paths
|
||||
+from ipapython.admintool import admin_cleanup_global_argv
|
||||
|
||||
logger = logging.getLogger(os.path.basename(__file__))
|
||||
|
||||
@@ -132,6 +133,7 @@ def parse_options():
|
||||
|
||||
options, args = parser.parse_args()
|
||||
safe_options = parser.get_safe_opts(options)
|
||||
+ admin_cleanup_global_argv(parser, options, sys.argv)
|
||||
|
||||
if args:
|
||||
parser.error("Too many arguments provided")
|
||||
diff --git a/install/tools/ipa-compat-manage.in b/install/tools/ipa-compat-manage.in
|
||||
index 459f39fc826bbe6becd8be3517235af343d4b0d9..9650abd6f83ebc0a8ef347fee83989d4e9f13f09 100644
|
||||
--- a/install/tools/ipa-compat-manage.in
|
||||
+++ b/install/tools/ipa-compat-manage.in
|
||||
@@ -24,13 +24,13 @@ from __future__ import print_function
|
||||
import sys
|
||||
from ipaplatform.paths import paths
|
||||
try:
|
||||
- from optparse import OptionParser # pylint: disable=deprecated-module
|
||||
from ipapython import ipautil, config
|
||||
from ipaserver.install import installutils
|
||||
from ipaserver.install.ldapupdate import LDAPUpdate
|
||||
from ipalib import api, errors
|
||||
from ipapython.ipa_log_manager import standard_logging_setup
|
||||
from ipapython.dn import DN
|
||||
+ from ipapython.admintool import admin_cleanup_global_argv
|
||||
except ImportError as e:
|
||||
print("""\
|
||||
There was a problem importing one of the required Python modules. The
|
||||
@@ -46,7 +46,8 @@ nis_config_dn = DN(('cn', 'NIS Server'), ('cn', 'plugins'), ('cn', 'config'))
|
||||
def parse_options():
|
||||
usage = "%prog [options] <enable|disable|status>\n"
|
||||
usage += "%prog [options]\n"
|
||||
- parser = OptionParser(usage=usage, formatter=config.IPAFormatter())
|
||||
+ parser = config.IPAOptionParser(usage=usage,
|
||||
+ formatter=config.IPAFormatter())
|
||||
|
||||
parser.add_option("-d", "--debug", action="store_true", dest="debug",
|
||||
help="Display debugging information about the update(s)")
|
||||
@@ -55,6 +56,7 @@ def parse_options():
|
||||
|
||||
config.add_standard_options(parser)
|
||||
options, args = parser.parse_args()
|
||||
+ admin_cleanup_global_argv(parser, options, sys.argv)
|
||||
|
||||
return options, args
|
||||
|
||||
diff --git a/install/tools/ipa-csreplica-manage.in b/install/tools/ipa-csreplica-manage.in
|
||||
index 6f248cc50f7f81b2014d629355f6f32d1d6ab7be..2fab27a94cfdbef8faadca82bc222bf96d212159 100644
|
||||
--- a/install/tools/ipa-csreplica-manage.in
|
||||
+++ b/install/tools/ipa-csreplica-manage.in
|
||||
@@ -32,8 +32,8 @@ from ipaserver.install import (replication, installutils, bindinstance,
|
||||
from ipalib import api, errors
|
||||
from ipalib.constants import FQDN
|
||||
from ipalib.util import has_managed_topology, print_replication_status
|
||||
-from ipapython import ipautil, ipaldap, version
|
||||
-from ipapython.admintool import ScriptError
|
||||
+from ipapython import ipautil, ipaldap, version, config
|
||||
+from ipapython.admintool import admin_cleanup_global_argv, ScriptError
|
||||
from ipapython.dn import DN
|
||||
|
||||
logger = logging.getLogger(os.path.basename(__file__))
|
||||
@@ -54,11 +54,10 @@ commands = {
|
||||
|
||||
|
||||
def parse_options():
|
||||
- from optparse import OptionParser # pylint: disable=deprecated-module
|
||||
-
|
||||
- parser = OptionParser(version=version.VERSION)
|
||||
+ parser = config.IPAOptionParser(version=version.VERSION)
|
||||
parser.add_option("-H", "--host", dest="host", help="starting host")
|
||||
- parser.add_option("-p", "--password", dest="dirman_passwd", help="Directory Manager password")
|
||||
+ parser.add_option("-p", "--password", dest="dirman_passwd", sensitive=True,
|
||||
+ help="Directory Manager password")
|
||||
parser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False,
|
||||
help="provide additional information")
|
||||
parser.add_option("-f", "--force", dest="force", action="store_true", default=False,
|
||||
@@ -66,6 +65,7 @@ def parse_options():
|
||||
parser.add_option("--from", dest="fromhost", help="Host to get data from")
|
||||
|
||||
options, args = parser.parse_args()
|
||||
+ admin_cleanup_global_argv(parser, options, sys.argv)
|
||||
|
||||
valid_syntax = False
|
||||
|
||||
diff --git a/install/tools/ipa-managed-entries.in b/install/tools/ipa-managed-entries.in
|
||||
index e3f121943eb3b18ca8f7f8bfeae7813cbc9bd753..ff2fd6a58ccb5b322f75008578fea81f561666fa 100644
|
||||
--- a/install/tools/ipa-managed-entries.in
|
||||
+++ b/install/tools/ipa-managed-entries.in
|
||||
@@ -24,7 +24,6 @@ import logging
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
-from optparse import OptionParser # pylint: disable=deprecated-module
|
||||
|
||||
from ipaplatform.paths import paths
|
||||
from ipapython import config
|
||||
@@ -32,6 +31,7 @@ from ipaserver.install import installutils
|
||||
from ipalib import api, errors
|
||||
from ipapython.ipa_log_manager import standard_logging_setup
|
||||
from ipapython.dn import DN
|
||||
+from ipapython.admintool import admin_cleanup_global_argv
|
||||
|
||||
logger = logging.getLogger(os.path.basename(__file__))
|
||||
|
||||
@@ -51,9 +51,10 @@ def parse_options():
|
||||
action="store_true",
|
||||
help="List available Managed Entries")
|
||||
parser.add_option("-p", "--password", dest="dirman_password",
|
||||
- help="Directory Manager password")
|
||||
+ sensitive=True, help="Directory Manager password")
|
||||
|
||||
options, args = parser.parse_args()
|
||||
+ admin_cleanup_global_argv(parser, options, sys.argv)
|
||||
|
||||
return options, args
|
||||
|
||||
diff --git a/install/tools/ipa-replica-conncheck.in b/install/tools/ipa-replica-conncheck.in
|
||||
index 8eee82483abc275cb37ad96ff272b6ee8192403f..81b7d13ac900031fa81356b894dc3eaaaee0f744 100644
|
||||
--- a/install/tools/ipa-replica-conncheck.in
|
||||
+++ b/install/tools/ipa-replica-conncheck.in
|
||||
@@ -23,15 +23,15 @@ from __future__ import print_function
|
||||
import logging
|
||||
|
||||
from ipapython import ipachangeconf
|
||||
-from ipapython.config import IPAOptionParser
|
||||
+from ipapython.config import (IPAOptionParser, OptionGroup,
|
||||
+ OptionValueError)
|
||||
+from ipapython.admintool import admin_cleanup_global_argv
|
||||
from ipapython.dn import DN
|
||||
from ipapython import version
|
||||
from ipapython import ipautil, certdb
|
||||
from ipalib import api, errors, x509
|
||||
from ipalib.constants import FQDN
|
||||
from ipaserver.install import installutils
|
||||
-# pylint: disable=deprecated-module
|
||||
-from optparse import OptionGroup, OptionValueError
|
||||
# pylint: enable=deprecated-module
|
||||
from ipapython.ipa_log_manager import standard_logging_setup
|
||||
import copy
|
||||
@@ -189,6 +189,7 @@ def parse_options():
|
||||
|
||||
options, _args = parser.parse_args()
|
||||
safe_options = parser.get_safe_opts(options)
|
||||
+ admin_cleanup_global_argv(parser, options, sys.argv)
|
||||
|
||||
if options.master and options.replica:
|
||||
parser.error("on-master and on-replica options are mutually exclusive!")
|
||||
diff --git a/install/tools/ipa-replica-manage.in b/install/tools/ipa-replica-manage.in
|
||||
index d6e6ef57c39af70f164d41662227af3dc2535f9c..7e5b31a598537f57c471729f22fdec4a5bedc03d 100644
|
||||
--- a/install/tools/ipa-replica-manage.in
|
||||
+++ b/install/tools/ipa-replica-manage.in
|
||||
@@ -43,6 +43,7 @@ from ipalib.util import (
|
||||
print_replication_status,
|
||||
verify_host_resolvable,
|
||||
)
|
||||
+from ipapython.admintool import admin_cleanup_global_argv
|
||||
from ipapython.ipa_log_manager import standard_logging_setup
|
||||
from ipapython.dn import DN
|
||||
from ipapython.config import IPAOptionParser
|
||||
@@ -84,7 +85,8 @@ class NoRUVsFound(Exception):
|
||||
def parse_options():
|
||||
parser = IPAOptionParser(version=version.VERSION)
|
||||
parser.add_option("-H", "--host", dest="host", help="starting host")
|
||||
- parser.add_option("-p", "--password", dest="dirman_passwd", help="Directory Manager password")
|
||||
+ parser.add_option("-p", "--password", dest="dirman_passwd", sensitive=True,
|
||||
+ help="Directory Manager password")
|
||||
parser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False,
|
||||
help="provide additional information")
|
||||
parser.add_option("-d", "--debug", dest="debug", action="store_true", default=False,
|
||||
@@ -95,7 +97,7 @@ def parse_options():
|
||||
help="DANGER: clean up references to a ghost master")
|
||||
parser.add_option("--binddn", dest="binddn", default=None, type="dn",
|
||||
help="Bind DN to use with remote server")
|
||||
- parser.add_option("--bindpw", dest="bindpw", default=None,
|
||||
+ parser.add_option("--bindpw", dest="bindpw", default=None, sensitive=True,
|
||||
help="Password for Bind DN to use with remote server")
|
||||
parser.add_option("--winsync", dest="winsync", action="store_true", default=False,
|
||||
help="This is a Windows Sync Agreement")
|
||||
@@ -103,13 +105,15 @@ def parse_options():
|
||||
help="Full path and filename of CA certificate to use with TLS/SSL to the remote server")
|
||||
parser.add_option("--win-subtree", dest="win_subtree", default=None,
|
||||
help="DN of Windows subtree containing the users you want to sync (default cn=Users,<domain suffix)")
|
||||
- parser.add_option("--passsync", dest="passsync", default=None,
|
||||
+ parser.add_option("--passsync", dest="passsync",
|
||||
+ default=None, sensitive=True,
|
||||
help="Password for the IPA system user used by the Windows PassSync plugin to synchronize passwords")
|
||||
parser.add_option("--from", dest="fromhost", help="Host to get data from")
|
||||
parser.add_option("--no-lookup", dest="nolookup", action="store_true", default=False,
|
||||
help="do not perform DNS lookup checks")
|
||||
|
||||
options, args = parser.parse_args()
|
||||
+ admin_cleanup_global_argv(parser, options, sys.argv)
|
||||
|
||||
valid_syntax = False
|
||||
|
||||
diff --git a/ipapython/admintool.py b/ipapython/admintool.py
|
||||
index dff9112eba4009d2fc1a6202756c6671ba4d909d..602223ef627c99f36a27d28fa712a6c196d7cb9f 100644
|
||||
--- a/ipapython/admintool.py
|
||||
+++ b/ipapython/admintool.py
|
||||
@@ -39,6 +39,45 @@ SERVER_NOT_CONFIGURED = 2
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
+def admin_cleanup_global_argv(option_parser, options, argv):
|
||||
+ """Takes option parser and generated options and scrubs sensitive arguments
|
||||
+ from the global program arguments. Note that this only works for GNU GLIBC
|
||||
+ as Python has no generic way to get access to the original argv values to
|
||||
+ modify them in place.
|
||||
+
|
||||
+ The code assumes Python behavior, e.g. there are two additional args in the
|
||||
+ list (/path/to/python -I ...) than what's passed as 'argv' here.
|
||||
+ """
|
||||
+ import ctypes
|
||||
+ import ctypes.util
|
||||
+ try:
|
||||
+ _c = ctypes.CDLL(ctypes.util.find_library("c"))
|
||||
+ if _c._name is None:
|
||||
+ return
|
||||
+ _argv = ctypes.POINTER(ctypes.c_voidp).in_dll(_c, "_dl_argv")
|
||||
+ # since we run as 'python -I <executable> ...', add two args
|
||||
+ _argc = len(argv) + 2
|
||||
+ all_options = []
|
||||
+ if '_get_all_options' in dir(option_parser):
|
||||
+ # OptParse parser
|
||||
+ all_options = option_parser._get_all_options()
|
||||
+ elif '_actions' in dir(option_parser):
|
||||
+ # ArgParse parser
|
||||
+ all_options = option_parser._actions
|
||||
+
|
||||
+ for opt in all_options:
|
||||
+ if getattr(opt, 'sensitive', False):
|
||||
+ v = getattr(options, opt.dest)
|
||||
+ for i in range(0, _argc):
|
||||
+ vi = ctypes.cast(_argv[i],
|
||||
+ ctypes.c_char_p
|
||||
+ ).value.decode('utf-8')
|
||||
+ if vi == v:
|
||||
+ ctypes.memset(_argv[i], ord('X'), len(v))
|
||||
+ except Exception:
|
||||
+ pass
|
||||
+
|
||||
+
|
||||
class ScriptError(Exception):
|
||||
"""An exception that records an error message and a return value
|
||||
"""
|
||||
@@ -148,6 +187,7 @@ class AdminTool:
|
||||
cls._option_parsers[cls] = cls.option_parser
|
||||
|
||||
options, args = cls.option_parser.parse_args(argv[1:])
|
||||
+ admin_cleanup_global_argv(cls.option_parser, options, argv)
|
||||
|
||||
command_class = cls.get_command_class(options, args)
|
||||
command = command_class(options, args)
|
||||
diff --git a/ipaserver/install/ipa_migrate.py b/ipaserver/install/ipa_migrate.py
|
||||
index f35629378490d3d45ca97f2aa5b4390c67d660ed..ece473bc8cb525e2d563356b5b274502d6b703e8 100644
|
||||
--- a/ipaserver/install/ipa_migrate.py
|
||||
+++ b/ipaserver/install/ipa_migrate.py
|
||||
@@ -28,6 +28,7 @@ from ipaplatform.paths import paths
|
||||
from ipapython.dn import DN
|
||||
from ipapython.ipaldap import LDAPClient, LDAPEntry, realm_to_ldapi_uri
|
||||
from ipapython.ipa_log_manager import standard_logging_setup
|
||||
+from ipapython.admintool import admin_cleanup_global_argv
|
||||
from ipaserver.install.ipa_migrate_constants import (
|
||||
DS_CONFIG, DB_OBJECTS, DS_INDEXES, BIND_DN, LOG_FILE_NAME,
|
||||
STRIP_OP_ATTRS, STRIP_ATTRS, STRIP_OC, PROD_ATTRS,
|
||||
@@ -284,6 +285,18 @@ class LDIFParser(ldif.LDIFParser):
|
||||
self.mc.process_db_entry(entry_dn=dn, entry_attrs=entry_attrs)
|
||||
|
||||
|
||||
+class SensitiveStoreAction(argparse._StoreAction):
|
||||
+ def __init__(self, *, sensitive, **options):
|
||||
+ super(SensitiveStoreAction, self).__init__(**options)
|
||||
+ self.sensitive = sensitive
|
||||
+
|
||||
+ def _get_kwargs(self):
|
||||
+ names = super(SensitiveStoreAction, self)._get_kwargs()
|
||||
+ sensitive_name = 'sensitive'
|
||||
+ names.extend((sensitive_name, getattr(self, sensitive_name)))
|
||||
+ return names
|
||||
+
|
||||
+
|
||||
#
|
||||
# Migrate IPA to IPA Class
|
||||
#
|
||||
@@ -344,7 +357,8 @@ class IPAMigrate():
|
||||
help='Password for the Bind DN. If a password '
|
||||
'is not provided then the user will be '
|
||||
'prompted to enter it',
|
||||
- default=None)
|
||||
+ default=None, sensitive=True,
|
||||
+ action=SensitiveStoreAction)
|
||||
parser.add_argument('-j', '--bind-pw-file',
|
||||
help='A text file containing the clear text '
|
||||
'password for the Bind DN', default=None)
|
||||
@@ -2128,6 +2142,7 @@ class IPAMigrate():
|
||||
parser = argparse.ArgumentParser(description=desc, allow_abbrev=True)
|
||||
self.add_options(parser)
|
||||
self.validate_options()
|
||||
+ admin_cleanup_global_argv(parser, self.args, sys.argv)
|
||||
|
||||
# Check for dryrun mode
|
||||
if self.args.dryrun or self.args.dryrun_record is not None:
|
||||
diff --git a/ipaserver/install/ipa_restore.py b/ipaserver/install/ipa_restore.py
|
||||
index 8d75a0e6beba09086bc2ce8c73f3bcfe81e52113..539501ab4f0c73571b680aeccf3854b511fd29dc 100644
|
||||
--- a/ipaserver/install/ipa_restore.py
|
||||
+++ b/ipaserver/install/ipa_restore.py
|
||||
@@ -185,7 +185,7 @@ class Restore(admintool.AdminTool):
|
||||
super(Restore, cls).add_options(parser, debug_option=True)
|
||||
|
||||
parser.add_option(
|
||||
- "-p", "--password", dest="password",
|
||||
+ "-p", "--password", dest="password", sensitive=True,
|
||||
help="Directory Manager password")
|
||||
parser.add_option(
|
||||
"--gpg-keyring", dest="gpg_keyring",
|
||||
diff --git a/ipaserver/install/ipa_server_certinstall.py b/ipaserver/install/ipa_server_certinstall.py
|
||||
index e9f680b1d1e505f89fc1611b8dbb3f84768f6781..76ad37ca7bcc62364379d56b21ead43c5248f5f1 100644
|
||||
--- a/ipaserver/install/ipa_server_certinstall.py
|
||||
+++ b/ipaserver/install/ipa_server_certinstall.py
|
||||
@@ -72,7 +72,7 @@ class ServerCertInstall(admintool.AdminTool):
|
||||
help="Name of the certificate to install")
|
||||
parser.add_option(
|
||||
"-p", "--dirman-password",
|
||||
- dest="dirman_password",
|
||||
+ dest="dirman_password", sensitive=True,
|
||||
help="Directory Manager password")
|
||||
|
||||
def validate_options(self):
|
||||
--
|
||||
2.47.1
|
||||
|
@ -0,0 +1,75 @@
|
||||
From d857fcfcc21481cdf06b8cce1685e141921d2fbf Mon Sep 17 00:00:00 2001
|
||||
From: Sumit Bose <sbose@redhat.com>
|
||||
Date: Wed, 27 Nov 2024 12:16:09 +0100
|
||||
Subject: [PATCH] ipa-otpd: use oidc_child's --client-secret-stdin option
|
||||
|
||||
To remove the client secret from the command line where it would be
|
||||
visible e.g. when calling ps it is now passed via stdin to oidc_child.
|
||||
|
||||
Fixes: CVE-2024-11029
|
||||
|
||||
Signed-off-by: Sumit Bose <sbose@redhat.com>
|
||||
---
|
||||
daemons/ipa-otpd/oauth2.c | 24 ++++++++++++++----------
|
||||
1 file changed, 14 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/daemons/ipa-otpd/oauth2.c b/daemons/ipa-otpd/oauth2.c
|
||||
index a33cf51715ca2a3e7a0cef871aed5cfbbd037598..52d7d7c9cb6c410bdbaa2e5eddccfea2204d3e69 100644
|
||||
--- a/daemons/ipa-otpd/oauth2.c
|
||||
+++ b/daemons/ipa-otpd/oauth2.c
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/random.h>
|
||||
+#include <sys/uio.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
@@ -93,6 +94,7 @@ static void oauth2_on_child_writable(verto_ctx *vctx, verto_ev *ev)
|
||||
(void)vctx; /* Unused */
|
||||
ssize_t io;
|
||||
struct child_ctx *child_ctx;
|
||||
+ struct iovec iov[3];
|
||||
|
||||
child_ctx = verto_get_private(ev);
|
||||
if (child_ctx == NULL) {
|
||||
@@ -102,15 +104,18 @@ static void oauth2_on_child_writable(verto_ctx *vctx, verto_ev *ev)
|
||||
}
|
||||
|
||||
if (child_ctx->oauth2_state == OAUTH2_GET_DEVICE_CODE) {
|
||||
- /* no input needed */
|
||||
- verto_del(ev);
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
+ io = write(verto_get_fd(ev), child_ctx->item->idp.ipaidpClientSecret,
|
||||
+ strlen(child_ctx->item->idp.ipaidpClientSecret));
|
||||
+ } else {
|
||||
+ iov[0].iov_base = child_ctx->item->idp.ipaidpClientSecret;
|
||||
+ iov[0].iov_len = strlen(child_ctx->item->idp.ipaidpClientSecret);
|
||||
+ iov[1].iov_base = "\n";
|
||||
+ iov[1].iov_len = 1;
|
||||
+ iov[2].iov_base = child_ctx->saved_item->oauth2.device_code_reply;
|
||||
+ iov[2].iov_len = strlen(child_ctx->saved_item->oauth2.device_code_reply);
|
||||
|
||||
- io = write(verto_get_fd(ev),
|
||||
- child_ctx->saved_item->oauth2.device_code_reply,
|
||||
- strlen(child_ctx->saved_item->oauth2.device_code_reply));
|
||||
+ io = writev(verto_get_fd(ev), iov, 3);
|
||||
+ }
|
||||
otpd_queue_item_free(child_ctx->saved_item);
|
||||
|
||||
if (io < 0) {
|
||||
@@ -429,8 +434,7 @@ int oauth2(struct otpd_queue_item **item, enum oauth2_state oauth2_state)
|
||||
args[args_idx++] = (*item)->idp.ipaidpClientID;
|
||||
|
||||
if ((*item)->idp.ipaidpClientSecret) {
|
||||
- args[args_idx++] = "--client-secret";
|
||||
- args[args_idx++] = (*item)->idp.ipaidpClientSecret;
|
||||
+ args[args_idx++] = "--client-secret-stdin";
|
||||
}
|
||||
|
||||
if ((*item)->idp.ipaidpScope) {
|
||||
--
|
||||
2.47.1
|
||||
|
69
SOURCES/0046-Fix-pylint-issue-in-ipatests-i18n.py.patch
Normal file
69
SOURCES/0046-Fix-pylint-issue-in-ipatests-i18n.py.patch
Normal file
@ -0,0 +1,69 @@
|
||||
From eef544c1d331bbe80852ebe8b5fc9bad0539b6fa Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Wed, 15 Jan 2025 15:39:20 +0100
|
||||
Subject: [PATCH] Fix pylint issue in ipatests/i18n.py
|
||||
|
||||
This file should not import ipa modules
|
||||
|
||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
---
|
||||
ipatests/i18n.py | 8 ++++----
|
||||
pylintrc | 3 ++-
|
||||
2 files changed, 6 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/ipatests/i18n.py b/ipatests/i18n.py
|
||||
index 57915c286be72124fa23380f97f3922496f00c22..49f5c4c3232346db3147bd7a5ba8056344ac907f 100644
|
||||
--- a/ipatests/i18n.py
|
||||
+++ b/ipatests/i18n.py
|
||||
@@ -22,6 +22,7 @@ from __future__ import print_function
|
||||
|
||||
# WARNING: Do not import ipa modules, this is also used as a
|
||||
# stand-alone script (invoked from po Makefile).
|
||||
+import optparse # pylint: disable=deprecated-module
|
||||
import sys
|
||||
import gettext
|
||||
import re
|
||||
@@ -29,7 +30,6 @@ import os
|
||||
import traceback
|
||||
import polib
|
||||
from collections import namedtuple
|
||||
-from ipapython import config
|
||||
|
||||
import six
|
||||
|
||||
@@ -722,9 +722,9 @@ usage ='''
|
||||
def main():
|
||||
global verbose, print_traceback, pedantic, show_strings
|
||||
|
||||
- parser = config.IPAOptionParser(usage=usage)
|
||||
+ parser = optparse.OptionParser(usage=usage)
|
||||
|
||||
- mode_group = config.OptionGroup(parser, 'Operational Mode',
|
||||
+ mode_group = optparse.OptionGroup(parser, 'Operational Mode',
|
||||
'You must select one these modes to run in')
|
||||
|
||||
mode_group.add_option('-g', '--test-gettext', action='store_const', const='test_gettext', dest='mode',
|
||||
@@ -748,7 +748,7 @@ def main():
|
||||
parser.add_option('--traceback', action='store_true', dest='print_traceback', default=False,
|
||||
help='print the traceback when an exception occurs')
|
||||
|
||||
- param_group = config.OptionGroup(parser, 'Run Time Parameters',
|
||||
+ param_group = optparse.OptionGroup(parser, 'Run Time Parameters',
|
||||
'These may be used to modify the run time defaults')
|
||||
|
||||
param_group.add_option('--test-lang', action='store', dest='test_lang', default='test',
|
||||
diff --git a/pylintrc b/pylintrc
|
||||
index 50278cc76031af68959a138f6ea185c4288c7155..8fadeffbdfdb8013135a17b3493ecc4dc7e5e001 100644
|
||||
--- a/pylintrc
|
||||
+++ b/pylintrc
|
||||
@@ -153,4 +153,5 @@ forbidden-imports=
|
||||
ipaplatform/:ipaclient:ipalib:ipaserver,
|
||||
ipapython/:ipaclient:ipalib:ipaserver
|
||||
ipatests/pytest_ipa:ipaserver:ipaclient.install:ipalib.install
|
||||
- ipatests/test_integration:ipaserver
|
||||
+ ipatests/test_integration:ipaserver,
|
||||
+ ipatests/i18n.py:ipapython
|
||||
--
|
||||
2.47.1
|
||||
|
@ -0,0 +1,51 @@
|
||||
From 45f96a0f978dfda0e2faa8360182a1dfd3122b94 Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Fri, 10 Jan 2025 13:22:29 +0100
|
||||
Subject: [PATCH] ipatests: skip test_ipahealthcheck_ds_configcheck for recent
|
||||
versions
|
||||
|
||||
389-ds removed the parameter nsslapd-logging-hr-timestamps-enabled
|
||||
in 2.5.3 and above. Skip the test that exercises the corresponding
|
||||
healthcheck.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9730
|
||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipatests/test_integration/test_ipahealthcheck.py | 12 +++++++++---
|
||||
1 file changed, 9 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py
|
||||
index cc51a5a6a62fbc50927fc2fc51f129a069e70b69..6b6f15aa433a423fe599118d2226e4c4ec62b13b 100644
|
||||
--- a/ipatests/test_integration/test_ipahealthcheck.py
|
||||
+++ b/ipatests/test_integration/test_ipahealthcheck.py
|
||||
@@ -18,7 +18,7 @@ import uuid
|
||||
|
||||
import pytest
|
||||
|
||||
-from ipalib import x509
|
||||
+from ipalib import errors, x509
|
||||
from ipapython.dn import DN
|
||||
from ipapython.ipaldap import realm_to_serverid
|
||||
from ipapython.certdb import NSS_SQL_FILES
|
||||
@@ -1146,8 +1146,14 @@ class TestIpaHealthCheck(IntegrationTest):
|
||||
)
|
||||
entry = ldap.get_entry(dn)
|
||||
entry.single_value["nsslapd-logging-hr-timestamps-enabled"] = 'off'
|
||||
- ldap.update_entry(entry)
|
||||
-
|
||||
+ try:
|
||||
+ ldap.update_entry(entry)
|
||||
+ except errors.DatabaseError as e:
|
||||
+ expected_msg = "Unknown attribute " \
|
||||
+ "nsslapd-logging-hr-timestamps-enabled"
|
||||
+ if expected_msg in e.message:
|
||||
+ pytest.skip(
|
||||
+ "389-ds removed nsslapd-logging-hr-timestamps-enabled")
|
||||
yield
|
||||
|
||||
entry = ldap.get_entry(dn)
|
||||
--
|
||||
2.47.1
|
||||
|
35
SOURCES/0048-ipatests-restart-dirsrv-after-time-jumps.patch
Normal file
35
SOURCES/0048-ipatests-restart-dirsrv-after-time-jumps.patch
Normal file
@ -0,0 +1,35 @@
|
||||
From ec94ee72714296c86ba1227a5a945a7ed0bc7fac Mon Sep 17 00:00:00 2001
|
||||
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Date: Thu, 16 Jan 2025 15:43:17 +0100
|
||||
Subject: [PATCH] ipatests: restart dirsrv after time jumps
|
||||
|
||||
The test for ipa-healthcheck is moving the date in the future.
|
||||
Restart the dirsrv instance because the LDAP server is
|
||||
sensitive to large time jumps.
|
||||
|
||||
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipatests/test_integration/test_ipahealthcheck.py | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/ipatests/test_integration/test_ipahealthcheck.py b/ipatests/test_integration/test_ipahealthcheck.py
|
||||
index 6b6f15aa433a423fe599118d2226e4c4ec62b13b..7c3f5857a477070d8a9b52c04d41f35ac580c97f 100644
|
||||
--- a/ipatests/test_integration/test_ipahealthcheck.py
|
||||
+++ b/ipatests/test_integration/test_ipahealthcheck.py
|
||||
@@ -1634,6 +1634,11 @@ class TestIpaHealthCheck(IntegrationTest):
|
||||
grace_date = datetime.strftime(grace_date, "%Y-%m-%d 00:00:01 Z")
|
||||
self.master.run_command(['date', '-s', grace_date])
|
||||
|
||||
+ # Restart dirsrv as it doesn't like time jumps
|
||||
+ instance = realm_to_serverid(self.master.domain.realm)
|
||||
+ cmd = ["systemctl", "restart", "dirsrv@{}".format(instance)]
|
||||
+ self.master.run_command(cmd)
|
||||
+
|
||||
for check in ("IPACertmongerExpirationCheck",
|
||||
"IPACertfileExpirationCheck",):
|
||||
execute_expiring_check(check)
|
||||
--
|
||||
2.47.1
|
||||
|
@ -0,0 +1,67 @@
|
||||
From f12c4ed600e9b35c930d386b37e36064fbf83968 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Fri, 17 Jan 2025 09:44:22 +0200
|
||||
Subject: [PATCH] ipa-otpd: do not pass OIDC client secret if there is none to
|
||||
pass
|
||||
|
||||
If there is no client secret specified for the OIDC client, don't push
|
||||
it to oidc_child via stdin. oidc_child does only expect client secret if
|
||||
--client-secret-stdin option was specified and we already specify it
|
||||
only if client secret is not empty.
|
||||
|
||||
In addition, if client secret is empty (it is a public OIDC client),
|
||||
then strlen(NULL) would crash in glibc internals. Avoid that!
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9734
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
daemons/ipa-otpd/oauth2.c | 29 +++++++++++++++++++----------
|
||||
1 file changed, 19 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/daemons/ipa-otpd/oauth2.c b/daemons/ipa-otpd/oauth2.c
|
||||
index 52d7d7c9cb6c410bdbaa2e5eddccfea2204d3e69..0eb43b2372701d47b9ef62cbbdb32b97a5f7a0ba 100644
|
||||
--- a/daemons/ipa-otpd/oauth2.c
|
||||
+++ b/daemons/ipa-otpd/oauth2.c
|
||||
@@ -104,17 +104,26 @@ static void oauth2_on_child_writable(verto_ctx *vctx, verto_ev *ev)
|
||||
}
|
||||
|
||||
if (child_ctx->oauth2_state == OAUTH2_GET_DEVICE_CODE) {
|
||||
- io = write(verto_get_fd(ev), child_ctx->item->idp.ipaidpClientSecret,
|
||||
- strlen(child_ctx->item->idp.ipaidpClientSecret));
|
||||
+ if (child_ctx->item->idp.ipaidpClientSecret != NULL) {
|
||||
+ io = write(verto_get_fd(ev), child_ctx->item->idp.ipaidpClientSecret,
|
||||
+ strlen(child_ctx->item->idp.ipaidpClientSecret));
|
||||
+ } else {
|
||||
+ io = 0;
|
||||
+ }
|
||||
} else {
|
||||
- iov[0].iov_base = child_ctx->item->idp.ipaidpClientSecret;
|
||||
- iov[0].iov_len = strlen(child_ctx->item->idp.ipaidpClientSecret);
|
||||
- iov[1].iov_base = "\n";
|
||||
- iov[1].iov_len = 1;
|
||||
- iov[2].iov_base = child_ctx->saved_item->oauth2.device_code_reply;
|
||||
- iov[2].iov_len = strlen(child_ctx->saved_item->oauth2.device_code_reply);
|
||||
-
|
||||
- io = writev(verto_get_fd(ev), iov, 3);
|
||||
+ int idx = 0;
|
||||
+ if (child_ctx->item->idp.ipaidpClientSecret != NULL) {
|
||||
+ iov[idx].iov_base = child_ctx->item->idp.ipaidpClientSecret;
|
||||
+ iov[idx].iov_len = strlen(child_ctx->item->idp.ipaidpClientSecret);
|
||||
+ idx++;
|
||||
+ iov[idx].iov_base = "\n";
|
||||
+ iov[idx].iov_len = 1;
|
||||
+ idx++;
|
||||
+ }
|
||||
+ iov[idx].iov_base = child_ctx->saved_item->oauth2.device_code_reply;
|
||||
+ iov[idx].iov_len = strlen(child_ctx->saved_item->oauth2.device_code_reply);
|
||||
+ idx++;
|
||||
+ io = writev(verto_get_fd(ev), iov, idx);
|
||||
}
|
||||
otpd_queue_item_free(child_ctx->saved_item);
|
||||
|
||||
--
|
||||
2.47.1
|
||||
|
@ -0,0 +1,165 @@
|
||||
From 4e43dd7cd30042588a2264fca98b6e6b9d4d25bb Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Date: Fri, 17 Jan 2025 12:33:54 +0200
|
||||
Subject: [PATCH] Migrate Keycloak tests to JDK 21 and Keycloak 26
|
||||
|
||||
Signed-off-by: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
.../pytest_ipa/integration/create_bridge.py | 2 +-
|
||||
.../pytest_ipa/integration/create_keycloak.py | 28 +++++++++----------
|
||||
ipatests/test_integration/test_idp.py | 4 +--
|
||||
ipatests/test_integration/test_sso.py | 4 +--
|
||||
4 files changed, 18 insertions(+), 20 deletions(-)
|
||||
|
||||
diff --git a/ipatests/pytest_ipa/integration/create_bridge.py b/ipatests/pytest_ipa/integration/create_bridge.py
|
||||
index 618c645feef86f846a60e5727e7777defc67624c..5dd2f305c2ba6f707ee40be12581ff62c951805b 100644
|
||||
--- a/ipatests/pytest_ipa/integration/create_bridge.py
|
||||
+++ b/ipatests/pytest_ipa/integration/create_bridge.py
|
||||
@@ -147,7 +147,7 @@ def setup_keycloak_scim_plugin(host, bridge_server):
|
||||
# Login to keycloak as admin
|
||||
kcadmin_sh = "/opt/keycloak/bin/kcadm.sh"
|
||||
kcadmin = [kcadmin_sh, "config", "credentials", "--server",
|
||||
- f"https://{host.hostname}:8443/auth/",
|
||||
+ f"https://{host.hostname}:8443",
|
||||
"--realm", "master", "--user", "admin",
|
||||
"--password", password]
|
||||
tasks.run_repeatedly(host, kcadmin, timeout=60)
|
||||
diff --git a/ipatests/pytest_ipa/integration/create_keycloak.py b/ipatests/pytest_ipa/integration/create_keycloak.py
|
||||
index 1340b95715c25f1bf1cbbf2e3c6e60731f3af08e..addade7594d7a1b8edefdb8c67ec4bc7abe70ef4 100644
|
||||
--- a/ipatests/pytest_ipa/integration/create_keycloak.py
|
||||
+++ b/ipatests/pytest_ipa/integration/create_keycloak.py
|
||||
@@ -6,10 +6,10 @@ from ipaplatform.paths import paths
|
||||
from ipatests.pytest_ipa.integration import tasks
|
||||
|
||||
|
||||
-def setup_keycloakserver(host, version='17.0.0'):
|
||||
+def setup_keycloakserver(host, version='26.1.0'):
|
||||
dir = "/opt/keycloak"
|
||||
password = host.config.admin_password
|
||||
- tasks.install_packages(host, ["unzip", "java-11-openjdk-headless",
|
||||
+ tasks.install_packages(host, ["unzip", "java-21-openjdk-headless",
|
||||
"openssl", "maven", "wget",
|
||||
"firefox", "xorg-x11-server-Xvfb"])
|
||||
# add keycloak system user/group and folder
|
||||
@@ -33,7 +33,7 @@ def setup_keycloakserver(host, version='17.0.0'):
|
||||
|
||||
key = os.path.join(paths.OPENSSL_PRIVATE_DIR, "keycloak.key")
|
||||
crt = os.path.join(paths.OPENSSL_PRIVATE_DIR, "keycloak.crt")
|
||||
- keystore = os.path.join(paths.OPENSSL_PRIVATE_DIR, "keycloak.store")
|
||||
+ keystore = os.path.join(paths.OPENSSL_PRIVATE_DIR, "keycloak.jks")
|
||||
|
||||
host.run_command(["ipa-getcert", "request", "-K",
|
||||
"HTTP/{0}".format(host.hostname),
|
||||
@@ -49,14 +49,13 @@ def setup_keycloakserver(host, version='17.0.0'):
|
||||
|
||||
# Setup keycloak service and config files
|
||||
contents = textwrap.dedent("""
|
||||
- KEYCLOAK_ADMIN=admin
|
||||
- KEYCLOAK_ADMIN_PASSWORD={admin_pswd}
|
||||
- KC_HOSTNAME={host}:8443
|
||||
+ KC_BOOTSTRAP_ADMIN_USERNAME=admin
|
||||
+ KC_BOOTSTRAP_ADMIN_PASSWORD={admin_pswd}
|
||||
+ KC_HOSTNAME=https://{host}:8443/
|
||||
KC_HTTPS_CERTIFICATE_FILE={crt}
|
||||
KC_HTTPS_CERTIFICATE_KEY_FILE={key}
|
||||
KC_HTTPS_TRUST_STORE_FILE={store}
|
||||
KC_HTTPS_TRUST_STORE_PASSWORD={store_pswd}
|
||||
- KC_HTTP_RELATIVE_PATH=/auth
|
||||
""").format(admin_pswd=password, host=host.hostname, crt=crt, key=key,
|
||||
store=keystore, store_pswd=password)
|
||||
host.put_file_contents("/etc/sysconfig/keycloak", contents)
|
||||
@@ -84,14 +83,13 @@ def setup_keycloakserver(host, version='17.0.0'):
|
||||
|
||||
# Run build stage first
|
||||
env_vars = textwrap.dedent("""
|
||||
- export KEYCLOAK_ADMIN=admin
|
||||
- export KC_HOSTNAME={hostname}:8443
|
||||
+ export KC_BOOTSTRAP_ADMIN_USERNAME=admin
|
||||
+ export KC_HOSTNAME=https://{hostname}:8443/
|
||||
export KC_HTTPS_CERTIFICATE_FILE=/etc/pki/tls/certs/keycloak.crt
|
||||
export KC_HTTPS_CERTIFICATE_KEY_FILE=/etc/pki/tls/private/keycloak.key
|
||||
- export KC_HTTPS_TRUST_STORE_FILE=/etc/pki/tls/private/keycloak.store
|
||||
+ export KC_HTTPS_TRUST_STORE_FILE=/etc/pki/tls/private/keycloak.jks
|
||||
export KC_HTTPS_TRUST_STORE_PASSWORD={STORE_PASS}
|
||||
- export KEYCLOAK_ADMIN_PASSWORD={ADMIN_PASS}
|
||||
- export KC_HTTP_RELATIVE_PATH=/auth
|
||||
+ export KC_BOOTSTRAP_ADMIN_PASSWORD={ADMIN_PASS}
|
||||
""").format(hostname=host.hostname, STORE_PASS=password,
|
||||
ADMIN_PASS=password)
|
||||
|
||||
@@ -112,7 +110,7 @@ def setup_keycloakserver(host, version='17.0.0'):
|
||||
host.run_command([kcadmin_sh, "config", "truststore",
|
||||
"--trustpass", password, keystore])
|
||||
kcadmin = [kcadmin_sh, "config", "credentials", "--server",
|
||||
- "https://{0}:8443/auth/".format(host.hostname),
|
||||
+ "https://{0}:8443/".format(host.hostname),
|
||||
"--realm", "master", "--user", "admin",
|
||||
"--password", password
|
||||
]
|
||||
@@ -133,7 +131,7 @@ def setup_keycloak_client(host):
|
||||
password = host.config.admin_password
|
||||
host.run_command(["/opt/keycloak/bin/kcreg.sh",
|
||||
"config", "credentials", "--server",
|
||||
- "https://{0}:8443/auth/".format(host.hostname),
|
||||
+ "https://{0}:8443/".format(host.hostname),
|
||||
"--realm", "master", "--user", "admin",
|
||||
"--password", password]
|
||||
)
|
||||
@@ -163,7 +161,7 @@ def setup_keycloak_client(host):
|
||||
def uninstall_keycloak(host):
|
||||
key = os.path.join(paths.OPENSSL_PRIVATE_DIR, "keycloak.key")
|
||||
crt = os.path.join(paths.OPENSSL_PRIVATE_DIR, "keycloak.crt")
|
||||
- keystore = os.path.join(paths.OPENSSL_PRIVATE_DIR, "keycloak.store")
|
||||
+ keystore = os.path.join(paths.OPENSSL_PRIVATE_DIR, "keycloak.jks")
|
||||
|
||||
host.run_command(["systemctl", "stop", "keycloak"], raiseonerr=False)
|
||||
host.run_command(["getcert", "stop-tracking", "-k", key, "-f", crt],
|
||||
diff --git a/ipatests/test_integration/test_idp.py b/ipatests/test_integration/test_idp.py
|
||||
index ca2fcecb22459685450f2ed6c3ac1b9b215170f6..76edc9458e4448e05362ff040b8dab7a53cd3054 100644
|
||||
--- a/ipatests/test_integration/test_idp.py
|
||||
+++ b/ipatests/test_integration/test_idp.py
|
||||
@@ -122,7 +122,7 @@ class TestIDPKeycloak(IntegrationTest):
|
||||
tasks.kinit_admin(self.master)
|
||||
cmd = ["ipa", "idp-add", "keycloakidp", "--provider=keycloak",
|
||||
"--client-id=ipa_oidc_client", "--org=master",
|
||||
- "--base-url={0}:8443/auth".format(self.client.hostname)]
|
||||
+ "--base-url={0}:8443".format(self.client.hostname)]
|
||||
self.master.run_command(cmd, stdin_text="{0}\n{0}".format(
|
||||
self.client.config.admin_password))
|
||||
tasks.user_add(self.master, 'keycloakuser',
|
||||
@@ -282,7 +282,7 @@ class TestIDPKeycloak(IntegrationTest):
|
||||
user = "backupuser"
|
||||
cmd = ["ipa", "idp-add", "testidp", "--provider=keycloak",
|
||||
"--client-id=ipa_oidc_client", "--org=master",
|
||||
- "--base-url={0}:8443/auth".format(self.client.hostname)]
|
||||
+ "--base-url={0}:8443".format(self.client.hostname)]
|
||||
self.master.run_command(cmd, stdin_text="{0}\n{0}".format(
|
||||
self.client.config.admin_password))
|
||||
|
||||
diff --git a/ipatests/test_integration/test_sso.py b/ipatests/test_integration/test_sso.py
|
||||
index 9708e9fa05a75cb2657c657b39b015249f3fd208..57c5a96bae986ee9721fc540d2be2cdc443e78fb 100644
|
||||
--- a/ipatests/test_integration/test_sso.py
|
||||
+++ b/ipatests/test_integration/test_sso.py
|
||||
@@ -18,7 +18,7 @@ from selenium.webdriver.support import expected_conditions as EC
|
||||
options = Options()
|
||||
options.headless = True
|
||||
driver = webdriver.Firefox(executable_path="/opt/geckodriver", options=options)
|
||||
-verification_uri = "https://{hostname}:8443/auth/realms/master/account/#/"
|
||||
+verification_uri = "https://{hostname}:8443/realms/master/account/#/"
|
||||
driver.get(verification_uri)
|
||||
|
||||
try:
|
||||
@@ -60,7 +60,7 @@ def keycloak_add_user(host, kcadm_pass, username, password=None):
|
||||
domain = host.domain.name
|
||||
kcadmin_sh = "/opt/keycloak/bin/kcadm.sh"
|
||||
kcadmin = [kcadmin_sh, "config", "credentials", "--server",
|
||||
- f"https://{host.hostname}:8443/auth/",
|
||||
+ f"https://{host.hostname}:8443",
|
||||
"--realm", "master", "--user", "admin",
|
||||
"--password", kcadm_pass]
|
||||
|
||||
--
|
||||
2.47.1
|
||||
|
@ -0,0 +1,162 @@
|
||||
From 9f30edef463237ba48efe45406626eb325bf6c39 Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Wed, 22 Jan 2025 13:19:43 -0500
|
||||
Subject: [PATCH] Apply certmonger_timeout to start_tracking and request_cert
|
||||
|
||||
We've seen that with some slow HSMs the default DBus timeout
|
||||
the HSM doesn't respond quickly enough to certmonger start
|
||||
tracking requests which fails the entire installation.
|
||||
|
||||
A first attempt was made to bump up the default to 30 seconds
|
||||
which turned out to not be long enough.
|
||||
|
||||
There is already a certmonger timeout defined in the API but it
|
||||
is 300 seconds so I was hesitant to use it. It could delay the
|
||||
actual failure of a blown install by 5 minutes. But it also gives
|
||||
the end user the flexibility to be able to control success over
|
||||
an installation so we'll go ahead and use it.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9725
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Mohammad Rizwan Yusuf <myusuf@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
---
|
||||
client/man/default.conf.5 | 10 ++++++++--
|
||||
ipalib/install/certmonger.py | 7 +++++--
|
||||
ipaserver/install/cainstance.py | 5 ++++-
|
||||
ipaserver/install/dogtaginstance.py | 18 ++++++++++++++++++
|
||||
ipaserver/install/service.py | 4 +++-
|
||||
5 files changed, 38 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/client/man/default.conf.5 b/client/man/default.conf.5
|
||||
index 3846de50c5d851471ea3ceed9fc38cb687c719e4..e0aec21f725d88ce2ba3cf52901fb15575892cde 100644
|
||||
--- a/client/man/default.conf.5
|
||||
+++ b/client/man/default.conf.5
|
||||
@@ -20,7 +20,7 @@
|
||||
.SH "NAME"
|
||||
default.conf \- IPA configuration file
|
||||
.SH "SYNOPSIS"
|
||||
-/etc/ipa/default.conf, ~/.ipa/default.conf, /etc/ipa/server.conf, /etc/ipa/cli.conf
|
||||
+/etc/ipa/default.conf, ~/.ipa/default.conf, /etc/ipa/server.conf, /etc/ipa/cli.conf, /etc/ipa/installer.conf, /etc/ipa/cli_installer.conf
|
||||
.SH "DESCRIPTION"
|
||||
The \fIdefault.conf \fRconfiguration file is used to set system\-wide defaults to be applied when running IPA clients and servers.
|
||||
|
||||
@@ -75,7 +75,7 @@ Specifies the hostname of the dogtag CA server. The default is the hostname of t
|
||||
Specifies the insecure CA end user port. The default is 8080.
|
||||
.TP
|
||||
.B certmonger_wait_timeout <seconds>
|
||||
-The time to wait for a certmonger request to complete during installation. The default value is 300 seconds.
|
||||
+The time to wait for a certmonger request to complete during installation. The default value is 300 seconds. To tune create/add to /etc/ipa/installer.conf.
|
||||
.TP
|
||||
.B context <context>
|
||||
Specifies the context that IPA is being executed in. IPA may operate differently depending on the context. The current defined contexts are cli, server and dns. Additionally this value is used to load /etc/ipa/\fBcontext\fR.conf to provide context\-specific configuration. For example, if you want to always perform client requests in verbose mode but do not want to have verbose enabled on the server, add the verbose option to \fI/etc/ipa/cli.conf\fR.
|
||||
@@ -263,6 +263,12 @@ system\-wide IPA client configuration file
|
||||
.TP
|
||||
.I /etc/ipa/server.conf
|
||||
system\-wide IPA server configuration file
|
||||
+.TP
|
||||
+.I /etc/ipa/installer.conf
|
||||
+IPA configuration used while installing an IPA server or replica
|
||||
+.TP
|
||||
+.I /etc/ipa/cli_installer.conf
|
||||
+IPA configuration used while installing an IPA client
|
||||
.SH "EXAMPLES"
|
||||
.TP
|
||||
An example of a context-specific configuration file is \fB/etc/ipa/dns.conf\fR to be used to increase debug output of the IPA DNSSEC daemons.
|
||||
diff --git a/ipalib/install/certmonger.py b/ipalib/install/certmonger.py
|
||||
index efc1ba4f42eab98df5fac51bafa3acc83ae91831..675b2c96ce8ebe4f06822ad587a4bca734a1be09 100644
|
||||
--- a/ipalib/install/certmonger.py
|
||||
+++ b/ipalib/install/certmonger.py
|
||||
@@ -477,7 +477,8 @@ def request_cert(
|
||||
request_parameters['cert-perms'] = perms[0]
|
||||
request_parameters['key-perms'] = perms[1]
|
||||
|
||||
- result = cm.obj_if.add_request(request_parameters, timeout=30)
|
||||
+ result = cm.obj_if.add_request(request_parameters,
|
||||
+ timeout=api.env.certmonger_wait_timeout)
|
||||
try:
|
||||
if result[0]:
|
||||
request = _cm_dbus_object(cm.bus, cm, result[1], DBUS_CM_REQUEST_IF,
|
||||
@@ -581,7 +582,9 @@ def start_tracking(
|
||||
if nss_user:
|
||||
params['nss-user'] = nss_user
|
||||
|
||||
- result = cm.obj_if.add_request(params, timeout=30)
|
||||
+ logger.debug("start tracking %s", params)
|
||||
+ result = cm.obj_if.add_request(params,
|
||||
+ timeout=api.env.certmonger_wait_timeout)
|
||||
try:
|
||||
if result[0]:
|
||||
request = _cm_dbus_object(cm.bus, cm, result[1], DBUS_CM_REQUEST_IF,
|
||||
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
|
||||
index e03a8c863e14782679e19c6887f5e220131e4234..76718036dbd317651edc98ce631405e42bf814d7 100644
|
||||
--- a/ipaserver/install/cainstance.py
|
||||
+++ b/ipaserver/install/cainstance.py
|
||||
@@ -513,7 +513,10 @@ class CAInstance(DogtagInstance):
|
||||
if ra_only:
|
||||
runtime = None
|
||||
else:
|
||||
- runtime = 180
|
||||
+ if self.tokenname:
|
||||
+ runtime = "HSM dependent"
|
||||
+ else:
|
||||
+ runtime = 180
|
||||
|
||||
try:
|
||||
self.start_creation(runtime=runtime)
|
||||
diff --git a/ipaserver/install/dogtaginstance.py b/ipaserver/install/dogtaginstance.py
|
||||
index 32a52dbedaa34b24c2658460f0ae889e7a37aa64..002053ed797beec829d324e80fc55b57cabf04be 100644
|
||||
--- a/ipaserver/install/dogtaginstance.py
|
||||
+++ b/ipaserver/install/dogtaginstance.py
|
||||
@@ -575,6 +575,24 @@ class DogtagInstance(service.Service):
|
||||
except RuntimeError as e:
|
||||
logger.error(
|
||||
"certmonger failed to start tracking certificate: %s", e)
|
||||
+ except dbus.exceptions.DBusException as e:
|
||||
+ if e._dbus_error_name == "org.freedesktop.DBus.Error.NoReply":
|
||||
+ logger.error(
|
||||
+ "Timeout encountered starting tracking of '%s'."
|
||||
+ "This timeout can be tuned using "
|
||||
+ "certmonger_wait_timeout in /etc/ipa/installer.conf.",
|
||||
+ nickname
|
||||
+ )
|
||||
+ if self.hsm_enabled:
|
||||
+ logger.error(
|
||||
+ "On an initial install failure this may leave "
|
||||
+ "certificates and keys on the HSM token. These "
|
||||
+ "need to be manually cleaned per your HSM-specific "
|
||||
+ "documentation before installing IPA again. On a "
|
||||
+ "replica install no clean-up should be done (it will "
|
||||
+ "destroy your installation."
|
||||
+ )
|
||||
+ raise
|
||||
|
||||
def stop_tracking_certificates(self):
|
||||
"""
|
||||
diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py
|
||||
index cf0f64ab9794111761adf735bc488269bd1814fc..7755a4f2ff5e33e61f85dc24b71fd05a1837cd5a 100644
|
||||
--- a/ipaserver/install/service.py
|
||||
+++ b/ipaserver/install/service.py
|
||||
@@ -59,6 +59,8 @@ def print_msg(message, output_fd=sys.stdout):
|
||||
|
||||
def format_seconds(seconds):
|
||||
"""Format a number of seconds as an English minutes+seconds message"""
|
||||
+ if type(seconds) is not int:
|
||||
+ return seconds
|
||||
parts = []
|
||||
minutes, seconds = divmod(seconds, 60)
|
||||
if minutes:
|
||||
@@ -660,7 +662,7 @@ class Service:
|
||||
else:
|
||||
end_message = "Done configuring %s." % self.service_desc
|
||||
|
||||
- if runtime is not None and runtime > 0:
|
||||
+ if runtime is not None or (type(runtime) is int and runtime > 0):
|
||||
self.print_msg('%s. Estimated time: %s' % (start_message,
|
||||
format_seconds(runtime)))
|
||||
else:
|
||||
--
|
||||
2.48.1
|
||||
|
1447
SOURCES/0052-Add-DNS-over-TLS-support.patch
Normal file
1447
SOURCES/0052-Add-DNS-over-TLS-support.patch
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,55 @@
|
||||
From 47ce0982249ee7ce12b38eae5ce3ee6a9b5df52e Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Tue, 4 Feb 2025 12:54:48 -0500
|
||||
Subject: [PATCH] Configure the pki-tomcatd service systemd timeout
|
||||
|
||||
IPA defines a startup timeout that is primarily used
|
||||
during installation to extend service start-up timeouts
|
||||
on slower systems.
|
||||
|
||||
This tends to work ok when runing pki-spawn but can fail when
|
||||
systemd is starting the tomcat service.
|
||||
|
||||
Use the value of startup_timeout to set TimeoutStartSec in
|
||||
the pki-tomcat systemd override file ipa.conf. This will
|
||||
preserve the necessary startup_timeout for all future restarts.
|
||||
|
||||
This was seen with a very slow HSM where installation was successful
|
||||
(pki-spawn) but pki-tomcatd startup timed out at the end of the
|
||||
installation.
|
||||
|
||||
To increase the value in installation one needs to create the file
|
||||
/etc/ipa/installer.conf with contents:
|
||||
|
||||
[global]
|
||||
startup_timeout = 300 (or whatever)
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9743
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
---
|
||||
ipaserver/install/cainstance.py | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
|
||||
index 76718036dbd317651edc98ce631405e42bf814d7..c8ecde8f2e9649d57012fcda937ee5816105df4e 100644
|
||||
--- a/ipaserver/install/cainstance.py
|
||||
+++ b/ipaserver/install/cainstance.py
|
||||
@@ -713,7 +713,12 @@ class CAInstance(DogtagInstance):
|
||||
f.write('[Service]\n')
|
||||
f.write('Environment=LC_ALL=C.UTF-8\n')
|
||||
f.write('ExecStartPost={}\n'.format(paths.IPA_PKI_WAIT_RUNNING))
|
||||
+ f.write('TimeoutStartSec=%d\n' % api.env.startup_timeout)
|
||||
tasks.systemd_daemon_reload()
|
||||
+ logger.info(
|
||||
+ "Set start up timeout of pki-tomcatd service to %d seconds",
|
||||
+ api.env.startup_timeout
|
||||
+ )
|
||||
|
||||
def safe_backup_config(self):
|
||||
"""
|
||||
--
|
||||
2.48.1
|
||||
|
@ -0,0 +1,84 @@
|
||||
From 22cbc5ed4889d6c66e2916d5acde582b1868fbc9 Mon Sep 17 00:00:00 2001
|
||||
From: Rob Crittenden <rcritten@redhat.com>
|
||||
Date: Mon, 10 Feb 2025 10:45:39 -0500
|
||||
Subject: [PATCH] Align startup_timeout with the systemd default and document
|
||||
it
|
||||
|
||||
We had it set to 120 seconds while the systemd default is 90.
|
||||
They should be the same because the first one that times out "wins".
|
||||
|
||||
Move where during the installation we create the systemd override
|
||||
file so that the timeout will be applied across all subsequent
|
||||
server starts during and post installation.
|
||||
|
||||
Fixes: https://pagure.io/freeipa/issue/9743
|
||||
|
||||
Signed-off-by: Rob Crittenden <rcritten@redhat.com>
|
||||
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
---
|
||||
client/man/default.conf.5 | 2 +-
|
||||
ipalib/constants.py | 5 +++--
|
||||
ipaserver/install/cainstance.py | 3 ++-
|
||||
3 files changed, 6 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/client/man/default.conf.5 b/client/man/default.conf.5
|
||||
index e0aec21f725d88ce2ba3cf52901fb15575892cde..461c60134124ed3e31e17ac350576487fda4c46e 100644
|
||||
--- a/client/man/default.conf.5
|
||||
+++ b/client/man/default.conf.5
|
||||
@@ -191,7 +191,7 @@ Specifies the IPA Server hostname.
|
||||
Skip client vs. server API version checking. Can lead to errors/strange behavior when newer clients talk to older servers. Use with caution.
|
||||
.TP
|
||||
.B startup_timeout <time in seconds>
|
||||
-Controls the amount of time waited when starting a service. The default value is 120 seconds.
|
||||
+Controls the amount of time waited when starting a service. The default value is 90 seconds, the same as the default systemd startup timeout. If configuring a CA the startup_timeout value will be added as an override for TimeoutStartSec in systemd. If installation times out when starting the CA create /etc/ipa/installer.conf with this value set.
|
||||
.TP
|
||||
.B startup_traceback <boolean>
|
||||
If the IPA server fails to start and this value is True the server will attempt to generate a python traceback to make identifying the underlying problem easier.
|
||||
diff --git a/ipalib/constants.py b/ipalib/constants.py
|
||||
index c90caa22149ec3d93d45fcb5480f7401e4555799..2e4c9a8336efae9e02febd6d04ec226c84af255f 100644
|
||||
--- a/ipalib/constants.py
|
||||
+++ b/ipalib/constants.py
|
||||
@@ -189,8 +189,9 @@ DEFAULT_CONFIG = (
|
||||
|
||||
# Time to wait for a service to start, in seconds.
|
||||
# Note that systemd has a DefaultTimeoutStartSec of 90 seconds. Higher
|
||||
- # values are not effective unless systemd is reconfigured, too.
|
||||
- ('startup_timeout', 120),
|
||||
+ # values are not effective unless systemd is reconfigured, too. Or you
|
||||
+ # can update the systemd service file with its own TimeoutStartSec.
|
||||
+ ('startup_timeout', 90),
|
||||
# How long http connection should wait for reply [seconds].
|
||||
('http_timeout', 30),
|
||||
# How long to wait for an entry to appear on a replica
|
||||
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
|
||||
index c8ecde8f2e9649d57012fcda937ee5816105df4e..3466c308829a576589874015542da9ea88bc2a2f 100644
|
||||
--- a/ipaserver/install/cainstance.py
|
||||
+++ b/ipaserver/install/cainstance.py
|
||||
@@ -453,6 +453,7 @@ class CAInstance(DogtagInstance):
|
||||
if promote:
|
||||
self.step("destroying installation admin user",
|
||||
self.teardown_admin)
|
||||
+ self.step("updating IPA configuration", update_ipa_conf)
|
||||
# Materialize config changes and new ACLs
|
||||
self.step("starting certificate server instance",
|
||||
self.start_instance)
|
||||
@@ -480,7 +481,6 @@ class CAInstance(DogtagInstance):
|
||||
self.step("configure certificate renewals", self.configure_renewal)
|
||||
self.step("Configure HTTP to proxy connections",
|
||||
self.http_proxy)
|
||||
- self.step("updating IPA configuration", update_ipa_conf)
|
||||
self.step("enabling CA instance", self.__enable_instance)
|
||||
if not promote:
|
||||
if self.clone:
|
||||
@@ -2453,6 +2453,7 @@ def update_ipa_conf(ca_host=None):
|
||||
parser.set('global', 'enable_ra', 'True')
|
||||
parser.set('global', 'ra_plugin', 'dogtag')
|
||||
parser.set('global', 'dogtag_version', '10')
|
||||
+ parser.set('global', 'startup_timeout', api.env.startup_timeout)
|
||||
if ca_host is None:
|
||||
parser.remove_option('global', 'ca_host')
|
||||
else:
|
||||
--
|
||||
2.48.1
|
||||
|
@ -0,0 +1,62 @@
|
||||
From 91353b10748f1153540c6f5447a80864dee59d7f Mon Sep 17 00:00:00 2001
|
||||
From: Antonio Torres <antorres@redhat.com>
|
||||
Date: Wed, 12 Feb 2025 09:48:58 +0100
|
||||
Subject: [PATCH] dns: only disable unbound when DoT is enabled
|
||||
|
||||
Ensure unbound is only stopped and disabled when DNS over TLS was
|
||||
enabled during installation.
|
||||
|
||||
Signed-off-by: Antonio Torres <antorres@redhat.com>
|
||||
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
|
||||
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||
---
|
||||
ipaserver/install/bindinstance.py | 11 +++++++----
|
||||
ipaserver/install/dns.py | 3 +++
|
||||
2 files changed, 10 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
|
||||
index 4f4ab9bbc66fcfd89354d6659cf9ac2bcaa270f6..0cc1f1325ce0a9dbdb09f4100a1a22bc4f24924a 100644
|
||||
--- a/ipaserver/install/bindinstance.py
|
||||
+++ b/ipaserver/install/bindinstance.py
|
||||
@@ -689,6 +689,8 @@ class BindInstance(service.Service):
|
||||
self.forward_policy = forward_policy
|
||||
self.reverse_zones = reverse_zones
|
||||
|
||||
+ self.sstore.backup_state("dns_over_tls", "enabled", dns_over_tls)
|
||||
+
|
||||
if not zonemgr:
|
||||
self.zonemgr = 'hostmaster.%s' % normalize_zone(self.domain)
|
||||
else:
|
||||
@@ -1377,10 +1379,11 @@ class BindInstance(service.Service):
|
||||
|
||||
self.named_conflict.unmask()
|
||||
|
||||
- certmonger.stop_tracking(certfile=paths.BIND_DNS_OVER_TLS_CRT)
|
||||
- certmonger.stop_tracking(certfile=paths.BIND_DNS_OVER_TLS_KEY)
|
||||
- services.knownservices.unbound.disable()
|
||||
- services.knownservices.unbound.stop()
|
||||
+ if self.sstore.restore_state("dns_over_tls", "enabled"):
|
||||
+ if not self.sstore.restore_state("dns_over_tls", "external_crt"):
|
||||
+ certmonger.stop_tracking(certfile=paths.BIND_DNS_OVER_TLS_CRT)
|
||||
+ services.knownservices["unbound"].disable()
|
||||
+ services.knownservices["unbound"].stop()
|
||||
|
||||
ipautil.remove_file(paths.NAMED_CONF_BAK)
|
||||
ipautil.remove_file(paths.NAMED_CUSTOM_CONF)
|
||||
diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py
|
||||
index 29ca0d2ff4efa8ad80784b393f49ac8ec0e03512..88aff19bcec11f778af5644167c32c45cbcab594 100644
|
||||
--- a/ipaserver/install/dns.py
|
||||
+++ b/ipaserver/install/dns.py
|
||||
@@ -457,6 +457,9 @@ def install(standalone, replica, options, api=api):
|
||||
|
||||
bind.create_instance()
|
||||
|
||||
+ bind.sstore.backup_state("dns_over_tls",
|
||||
+ "external_crt",
|
||||
+ bool(options.dns_over_tls_cert))
|
||||
if options.dns_over_tls:
|
||||
print("Setting up DNS over TLS")
|
||||
_setup_dns_over_tls(options)
|
||||
--
|
||||
2.48.1
|
||||
|
@ -1,69 +0,0 @@
|
||||
From 0d44e959e5bbe822b51137a8e7cf48fa25533805 Mon Sep 17 00:00:00 2001
|
||||
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
Date: Fri, 10 Dec 2021 12:15:36 -0300
|
||||
Subject: [PATCH] Revert "freeipa.spec: depend on bind-dnssec-utils"
|
||||
|
||||
This reverts commit f89d59b6e18b54967682f6a37ce92ae67ab3fcda.
|
||||
---
|
||||
freeipa.spec.in | 4 +---
|
||||
ipaplatform/base/paths.py | 2 +-
|
||||
ipaplatform/fedora/paths.py | 1 +
|
||||
ipaserver/dnssec/bindmgr.py | 1 -
|
||||
4 files changed, 3 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/freeipa.spec.in b/freeipa.spec.in
|
||||
index 8f5c370e5..e20edb7bc 100755
|
||||
--- a/freeipa.spec.in
|
||||
+++ b/freeipa.spec.in
|
||||
@@ -576,11 +576,9 @@ Requires: %{name}-server = %{version}-%{release}
|
||||
Requires: bind-dyndb-ldap >= 11.2-2
|
||||
Requires: bind >= %{bind_version}
|
||||
Requires: bind-utils >= %{bind_version}
|
||||
-# bind-dnssec-utils is required by the OpenDNSSec integration
|
||||
-# https://pagure.io/freeipa/issue/9026
|
||||
-Requires: bind-dnssec-utils >= %{bind_version}
|
||||
%if %{with bind_pkcs11}
|
||||
Requires: bind-pkcs11 >= %{bind_version}
|
||||
+Requires: bind-pkcs11-utils >= %{bind_version}
|
||||
%else
|
||||
Requires: softhsm >= %{softhsm_version}
|
||||
Requires: openssl-pkcs11 >= %{openssl_pkcs11_version}
|
||||
diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py
|
||||
index 7d21367ec..42a47f1df 100644
|
||||
--- a/ipaplatform/base/paths.py
|
||||
+++ b/ipaplatform/base/paths.py
|
||||
@@ -259,7 +259,6 @@ class BasePathNamespace:
|
||||
IPA_PKI_RETRIEVE_KEY = "/usr/libexec/ipa/ipa-pki-retrieve-key"
|
||||
IPA_HTTPD_PASSWD_READER = "/usr/libexec/ipa/ipa-httpd-pwdreader"
|
||||
IPA_PKI_WAIT_RUNNING = "/usr/libexec/ipa/ipa-pki-wait-running"
|
||||
- DNSSEC_KEYFROMLABEL = "/usr/sbin/dnssec-keyfromlabel"
|
||||
+ DNSSEC_KEYFROMLABEL = "/usr/sbin/dnssec-keyfromlabel-pkcs11"
|
||||
- DNSSEC_KEYFROMLABEL_9_17 = "/usr/bin/dnssec-keyfromlabel"
|
||||
GETSEBOOL = "/usr/sbin/getsebool"
|
||||
GROUPADD = "/usr/sbin/groupadd"
|
||||
diff --git a/ipaplatform/fedora/paths.py b/ipaplatform/fedora/paths.py
|
||||
index 4e993c063..92a948966 100644
|
||||
--- a/ipaplatform/fedora/paths.py
|
||||
+++ b/ipaplatform/fedora/paths.py
|
||||
@@ -36,6 +36,7 @@ class FedoraPathNamespace(RedHatPathNamespace):
|
||||
NAMED_CRYPTO_POLICY_FILE = "/etc/crypto-policies/back-ends/bind.config"
|
||||
if HAS_NFS_CONF:
|
||||
SYSCONFIG_NFS = '/etc/nfs.conf'
|
||||
+ DNSSEC_KEYFROMLABEL = "/usr/sbin/dnssec-keyfromlabel"
|
||||
|
||||
|
||||
paths = FedoraPathNamespace()
|
||||
diff --git a/ipaserver/dnssec/bindmgr.py b/ipaserver/dnssec/bindmgr.py
|
||||
index 0c79cc03d..a15c0e601 100644
|
||||
--- a/ipaserver/dnssec/bindmgr.py
|
||||
+++ b/ipaserver/dnssec/bindmgr.py
|
||||
@@ -127,7 +127,6 @@ class BINDMgr:
|
||||
)
|
||||
cmd = [
|
||||
paths.DNSSEC_KEYFROMLABEL,
|
||||
- '-E', 'pkcs11',
|
||||
'-K', workdir,
|
||||
'-a', attrs['idnsSecAlgorithm'][0],
|
||||
'-l', uri
|
||||
--
|
||||
2.31.1
|
@ -1,60 +0,0 @@
|
||||
From 7807bcc55b4927fc327830d2237200772d2e1106 Mon Sep 17 00:00:00 2001
|
||||
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
Date: Fri, 17 Jun 2022 15:40:04 -0300
|
||||
Subject: [PATCH] webui IdP: Remove arrow notation due to uglify-js limitation.
|
||||
|
||||
uglify-js 2.x series do not support ECMAScript 6 arrow notation ('=>')
|
||||
for callback definition.
|
||||
|
||||
This patch changes the arrow definition callbacks for regular anonymous
|
||||
function definitions.
|
||||
---
|
||||
install/ui/src/freeipa/idp.js | 10 +++++-----
|
||||
1 file changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/install/ui/src/freeipa/idp.js b/install/ui/src/freeipa/idp.js
|
||||
index ada09c075..be3c4f0e6 100644
|
||||
--- a/install/ui/src/freeipa/idp.js
|
||||
+++ b/install/ui/src/freeipa/idp.js
|
||||
@@ -227,7 +227,7 @@ IPA.add_idp_policy = function() {
|
||||
// For custom template we show custom fields
|
||||
// and mark all of them required and passed to the RPC
|
||||
// If show_custom is false, the opposite happens
|
||||
- custom_fields.forEach(fname => {
|
||||
+ custom_fields.forEach(function(fname) {
|
||||
widget_f = that.container.fields.get_field(fname);
|
||||
widget_f.set_required(show_custom);
|
||||
widget_f.set_enabled(show_custom);
|
||||
@@ -235,7 +235,7 @@ IPA.add_idp_policy = function() {
|
||||
});
|
||||
|
||||
// For template fields we show them if custom aren't shown
|
||||
- template_fields.forEach(fname => {
|
||||
+ template_fields.forEach(function(fname) {
|
||||
widget_f = that.container.fields.get_field(fname);
|
||||
widget_f.set_enabled(!show_custom);
|
||||
widget_f.widget.set_visible(!show_custom);
|
||||
@@ -252,7 +252,7 @@ IPA.add_idp_policy = function() {
|
||||
var value = prov_f.get_value()[0];
|
||||
|
||||
// First, clear template fields from the previous provider choice
|
||||
- template_fields.forEach(fname => {
|
||||
+ template_fields.forEach(function(fname) {
|
||||
widget_f = that.container.fields.get_field(fname);
|
||||
widget_f.widget.set_visible(false);
|
||||
widget_f.set_required(false);
|
||||
@@ -260,9 +260,9 @@ IPA.add_idp_policy = function() {
|
||||
});
|
||||
|
||||
// Second, enable and get required template-specific fields
|
||||
- idp.templates.forEach(idp_v => {
|
||||
+ idp.templates.forEach(function(idp_v) {
|
||||
if (idp_v['value'] == value) {
|
||||
- idp_v['fields'].forEach(fname => {
|
||||
+ idp_v['fields'].forEach(function(fname) {
|
||||
widget_f = that.container.fields.get_field(fname);
|
||||
widget_f.set_required(true);
|
||||
widget_f.set_enabled(true);
|
||||
--
|
||||
2.36.1
|
||||
|
@ -1,120 +0,0 @@
|
||||
From 9a33838407f244e481523fe643bc0626874e8b1a Mon Sep 17 00:00:00 2001
|
||||
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
|
||||
Date: Mon, 19 Dec 2022 14:57:03 -0300
|
||||
Subject: [PATCH] Revert "DNSResolver: Fix use of nameservers with ports"
|
||||
|
||||
This reverts commit 5e2e4664aec641886923c2bec61ce25b96edb62a.
|
||||
|
||||
diff --git a/ipapython/dnsutil.py b/ipapython/dnsutil.py
|
||||
index 58de365ab..4baeaf8cc 100644
|
||||
--- a/ipapython/dnsutil.py 2023-05-19 05:12:52.471239297 -0300
|
||||
+++ b/ipapython/dnsutil.py 2023-05-24 12:20:13.588867053 -0300
|
||||
@@ -145,55 +145,6 @@
|
||||
nameservers.remove(ipv4_loopback)
|
||||
self.nameservers = nameservers
|
||||
|
||||
- @property
|
||||
- def nameservers(self):
|
||||
- return self._nameservers
|
||||
-
|
||||
- @nameservers.setter
|
||||
- def nameservers(self, nameservers):
|
||||
- """
|
||||
- *nameservers*, a ``list`` of nameservers with optional ports:
|
||||
- "SERVER_IP port PORT_NUMBER".
|
||||
-
|
||||
- Overloads dns.resolver.Resolver.nameservers setter to split off ports
|
||||
- into nameserver_ports after setting nameservers successfully with the
|
||||
- setter in dns.resolver.Resolver.
|
||||
- """
|
||||
- # Get nameserver_ports if it is already set
|
||||
- if hasattr(self, "nameserver_ports"):
|
||||
- nameserver_ports = self.nameserver_ports
|
||||
- else:
|
||||
- nameserver_ports = {}
|
||||
-
|
||||
- # Check nameserver items in list and split out converted port number
|
||||
- # into nameserver_ports: { nameserver: port }
|
||||
- if isinstance(nameservers, list):
|
||||
- _nameservers = []
|
||||
- for nameserver in nameservers:
|
||||
- splits = nameserver.split()
|
||||
- if len(splits) == 3 and splits[1] == "port":
|
||||
- nameserver = splits[0]
|
||||
- try:
|
||||
- port = int(splits[2])
|
||||
- if port < 0 or port > 65535:
|
||||
- raise ValueError()
|
||||
- except ValueError:
|
||||
- raise ValueError(
|
||||
- "invalid nameserver: %s is not a valid port" %
|
||||
- splits[2])
|
||||
- nameserver_ports[nameserver] = port
|
||||
- _nameservers.append(nameserver)
|
||||
- nameservers = _nameservers
|
||||
-
|
||||
- # Call dns.resolver.Resolver.nameservers setter
|
||||
- if hasattr(dns.resolver.Resolver, "nameservers"):
|
||||
- dns.resolver.Resolver.nameservers.__set__(self, nameservers)
|
||||
- else:
|
||||
- # old dnspython (<2) doesn't have 'nameservers' property
|
||||
- self._nameservers = nameservers
|
||||
- # Set nameserver_ports after successfull call to setter
|
||||
- self.nameserver_ports = nameserver_ports
|
||||
-
|
||||
|
||||
class DNSZoneAlreadyExists(dns.exception.DNSException):
|
||||
supp_kwargs = {'zone', 'ns'}
|
||||
diff --git a/ipatests/test_ipapython/test_dnsutil.py b/ipatests/test_ipapython/test_dnsutil.py
|
||||
index 9070d89ad..5e7a46197 100644
|
||||
--- a/ipatests/test_ipapython/test_dnsutil.py
|
||||
+++ b/ipatests/test_ipapython/test_dnsutil.py
|
||||
@@ -101,48 +101,3 @@ class TestSortURI:
|
||||
assert dnsutil.sort_prio_weight([h3, h2, h1]) == [h1, h2, h3]
|
||||
assert dnsutil.sort_prio_weight([h3, h3, h3]) == [h3]
|
||||
assert dnsutil.sort_prio_weight([h2, h2, h1, h1]) == [h1, h2]
|
||||
-
|
||||
-
|
||||
-class TestDNSResolver:
|
||||
- @pytest.fixture(name="res")
|
||||
- def resolver(self):
|
||||
- """Resolver that doesn't read /etc/resolv.conf
|
||||
-
|
||||
- /etc/resolv.conf is not mandatory on systems
|
||||
- """
|
||||
- return dnsutil.DNSResolver(configure=False)
|
||||
-
|
||||
- def test_nameservers(self, res):
|
||||
- res.nameservers = ["4.4.4.4", "8.8.8.8"]
|
||||
- assert res.nameservers == ["4.4.4.4", "8.8.8.8"]
|
||||
-
|
||||
- def test_nameservers_with_ports(self, res):
|
||||
- res.nameservers = ["4.4.4.4 port 53", "8.8.8.8 port 8053"]
|
||||
- assert res.nameservers == ["4.4.4.4", "8.8.8.8"]
|
||||
- assert res.nameserver_ports == {"4.4.4.4": 53, "8.8.8.8": 8053}
|
||||
-
|
||||
- res.nameservers = ["4.4.4.4 port 53", "8.8.8.8 port 8053"]
|
||||
- assert res.nameservers == ["4.4.4.4", "8.8.8.8"]
|
||||
- assert res.nameserver_ports == {"4.4.4.4": 53, "8.8.8.8": 8053}
|
||||
-
|
||||
- def test_nameservers_with_bad_ports(self, res):
|
||||
- try:
|
||||
- res.nameservers = ["4.4.4.4 port a"]
|
||||
- except ValueError:
|
||||
- pass
|
||||
- else:
|
||||
- pytest.fail("No fail on bad port a")
|
||||
-
|
||||
- try:
|
||||
- res.nameservers = ["4.4.4.4 port -1"]
|
||||
- except ValueError:
|
||||
- pass
|
||||
- else:
|
||||
- pytest.fail("No fail on bad port -1")
|
||||
-
|
||||
- try:
|
||||
- res.nameservers = ["4.4.4.4 port 65536"]
|
||||
- except ValueError:
|
||||
- pass
|
||||
- else:
|
||||
- pytest.fail("No fail on bad port 65536")
|
16
SOURCES/freeipa-4.12.2.tar.gz.asc
Normal file
16
SOURCES/freeipa-4.12.2.tar.gz.asc
Normal file
@ -0,0 +1,16 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQIzBAABCAAdFiEEL88tWdi+3Yi1YO6/QPd0nE8v3u0FAmbGIAgACgkQQPd0nE8v
|
||||
3u25Hg//cSLyagXQ6cDnpR4TiLBTrbRu8rycJt8qWK2c+VtnjFb5jWHz8P4dyQ2t
|
||||
liduXvT9SLSuwaDRySNGgWrA1LDxm+VLv0pyjuCBX59T7EHwz3mtmBDA2WHpgOZ1
|
||||
q2owCbhZRHtEd53T8bQBi8zUbqOqZoU/yc03Vt8h5XcrA5Pxxlm9sSIzC0RHToud
|
||||
uTGLNyIUQR5el+kfvUkBuyuRB0LMqZNo/xFcmV4lc0VO37EA07nSleNliYE06fwi
|
||||
soDR+qrpt4I4vpCVjtbQsJF5dtaFpmHbbshmIudyriBBlukmpXvlFXkBXdZruZKW
|
||||
x/+abovaGgwdx2BdMBAPXrSByzXPNGQhF0jfC7VUS5NTehWQ3yjoTylOgwyYjsCp
|
||||
zKAH4KJeDEnn6Epb+DhC8DxQy9JaviALYkYZDw6qt9JkMiZUudnPsEz/KZkk/F5C
|
||||
VLKTI6vv+6wXUMt0NjUyuvcb3xHpks8RuZ7pbxoS09kceSC4jAsgeFc6JI+F5QC5
|
||||
1IO+yrwGj/s22lusb8BPEEM9DQQI27V5Ljeb3NxdASZE4cgJAOIyIe8aUeEf8Q6Z
|
||||
a696Slrhy8uuQkMXCUMKrrK1E7bHgIZszdy9rNM4JTYVWjLNXstkErqdmbeQ1zUN
|
||||
VyT+DT8dK/fqvH9NBpyUNbXtzpSm+bfAqWOJKvQrTnyknfIGdKw=
|
||||
=ReWc
|
||||
-----END PGP SIGNATURE-----
|
@ -1,16 +0,0 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
iQIzBAABCAAdFiEE11Z2TU1+KXxtrRFyaYdvcqbi008FAmVbZU0ACgkQaYdvcqbi
|
||||
009Fgw/+PzHGNOJPs67TtoYITV/3ZCzMyrYTcazVACjD61Zw7JBgbZzZpQXxBSbj
|
||||
7QWpNJa3P2JFtv2qOUXJto40mOGpMynyYpuYs4CtyJ86eHTUJyYTFppBmCzzozhT
|
||||
2C2BeKKjzV8OOWQ7yO/2BTEZ7KtOcIr4ZI7iZCnLJF9Yt8x7TURjGRqxsHwT62Ip
|
||||
vcrtm0LkkYv/fQ6pFZZfinKU1OBrZphwHMCU4Mlv411iQg4+NOxLSsVU/kegeKIO
|
||||
adp4Y9g5dfAfdXEXb2Zt7gkmLaWMgf+XNSFDL/wkzRYt74HKwvbIPJQlTZ6pqLxQ
|
||||
yTtiHGuMb7xNDWolpoueo1/lbxaHRRGJaSPs7zUht3IBxb7hiF65Gm3UaJhoeAXc
|
||||
gVleZf/+0titOdkRfTD2N0P0hli7gaiRrbpw8K4joxMFpYrQGUxD8SI376gkOj6o
|
||||
5RWSioPoG9txNM7Co+lVpci7WHhL+Tmhf1SlHyVJGKoNe/z4VHnjHeYlFWRVdDEI
|
||||
OOupZzJQoLnso3lTwR5VEN8xGURnhbGV4MdUfD/6FhwmyHiPlYkytdZIsGsNDOab
|
||||
978PPaKcIpbsZ4gUhshcbn7qaY809lNSpMtg8saYOP4J/5Nu+i9X5bJqOmoX0rKa
|
||||
gAJDY5har+lExRnTEdYEGVB8qen5lqi8r1oYjnDpkSpq6BRoAHA=
|
||||
=uQom
|
||||
-----END PGP SIGNATURE-----
|
3645
SPECS/freeipa.spec
Normal file
3645
SPECS/freeipa.spec
Normal file
File diff suppressed because it is too large
Load Diff
5420
SPECS/ipa.spec
5420
SPECS/ipa.spec
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user