Compare commits
No commits in common. "c8-beta-stream-DL1" and "c8-stream-DL1" have entirely different histories.
c8-beta-st
...
c8-stream-
@ -40,12 +40,11 @@ index 06d511c76..dbb98dba6 100644
|
|||||||
#include "ipa_krb5.h"
|
#include "ipa_krb5.h"
|
||||||
#include "ipa_hostname.h"
|
#include "ipa_hostname.h"
|
||||||
+#include <kadm5/admin.h>
|
+#include <kadm5/admin.h>
|
||||||
|
|
||||||
#define IPADB_GLOBAL_CONFIG_CACHE_TIME 60
|
#define IPADB_GLOBAL_CONFIG_CACHE_TIME 60
|
||||||
|
|
||||||
@@ -207,6 +208,19 @@ static const struct {
|
@@ -207,5 +208,18 @@ static const struct {
|
||||||
{ "idp", IPADB_USER_AUTH_IDP },
|
{ "idp", IPADB_USER_AUTH_IDP },
|
||||||
{ "passkey", IPADB_USER_AUTH_PASSKEY },
|
|
||||||
{ }
|
{ }
|
||||||
+},
|
+},
|
||||||
+ objclass_table[] = {
|
+ objclass_table[] = {
|
||||||
@ -61,10 +60,10 @@ index 06d511c76..dbb98dba6 100644
|
|||||||
+ { KADM5_HIST_PRINCIPAL, IPADB_USER_AUTH_PASSWORD },
|
+ { KADM5_HIST_PRINCIPAL, IPADB_USER_AUTH_PASSWORD },
|
||||||
+ { }
|
+ { }
|
||||||
};
|
};
|
||||||
|
|
||||||
void ipadb_parse_user_auth(LDAP *lcontext, LDAPMessage *le,
|
void ipadb_parse_user_auth(LDAP *lcontext, LDAPMessage *le,
|
||||||
@@ -217,17 +231,49 @@ 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;
|
*userauth = IPADB_USER_AUTH_NONE;
|
||||||
vals = ldap_get_values_len(lcontext, le, IPA_USER_AUTH_TYPE);
|
vals = ldap_get_values_len(lcontext, le, IPA_USER_AUTH_TYPE);
|
||||||
- if (!vals)
|
- if (!vals)
|
||||||
@ -121,7 +120,7 @@ index 06d511c76..dbb98dba6 100644
|
|||||||
/* If password auth is enabled, enable hardened policy too. */
|
/* If password auth is enabled, enable hardened policy too. */
|
||||||
if (*userauth & IPADB_USER_AUTH_PASSWORD) {
|
if (*userauth & IPADB_USER_AUTH_PASSWORD) {
|
||||||
*userauth |= IPADB_USER_AUTH_HARDENED;
|
*userauth |= IPADB_USER_AUTH_HARDENED;
|
||||||
--
|
--
|
||||||
2.43.0
|
2.43.0
|
||||||
|
|
||||||
|
|
||||||
@ -163,7 +162,7 @@ index 436ee0e62..2802221c7 100644
|
|||||||
pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_PKINIT]);
|
pol_limits = &(ied->pol_limits[IPADB_USER_AUTH_IDX_PKINIT]);
|
||||||
} else if (strcmp(auth_indicator, "hardened") == 0) {
|
} else if (strcmp(auth_indicator, "hardened") == 0) {
|
||||||
valid_auth_indicators++;
|
valid_auth_indicators++;
|
||||||
--
|
--
|
||||||
2.43.0
|
2.43.0
|
||||||
|
|
||||||
|
|
||||||
@ -188,14 +187,14 @@ index dbb98dba6..4e6cacf24 100644
|
|||||||
@@ -195,6 +195,9 @@ done:
|
@@ -195,6 +195,9 @@ done:
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
+/* In this table all _AUTH_PASSWORD entries will be
|
+/* In this table all _AUTH_PASSWORD entries will be
|
||||||
+ * expanded to include _AUTH_HARDENED in ipadb_parse_user_auth()
|
+ * expanded to include _AUTH_HARDENED in ipadb_parse_user_auth()
|
||||||
+ * which means there is no need to explicitly add it here */
|
+ * which means there is no need to explicitly add it here */
|
||||||
static const struct {
|
static const struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
enum ipadb_user_auth flag;
|
enum ipadb_user_auth flag;
|
||||||
--
|
--
|
||||||
2.43.0
|
2.43.0
|
||||||
|
|
||||||
|
|
||||||
@ -230,7 +229,7 @@ index caa0e6a34..5c2e7af02 100644
|
|||||||
@@ -23,6 +23,24 @@ class TestPkinitClientInstall(IntegrationTest):
|
@@ -23,6 +23,24 @@ class TestPkinitClientInstall(IntegrationTest):
|
||||||
def install(cls, mh):
|
def install(cls, mh):
|
||||||
tasks.install_master(cls.master)
|
tasks.install_master(cls.master)
|
||||||
|
|
||||||
+ def enforce_password_and_otp(self):
|
+ def enforce_password_and_otp(self):
|
||||||
+ """enforce otp by default and password for admin """
|
+ """enforce otp by default and password for admin """
|
||||||
+ self.master.run_command(
|
+ self.master.run_command(
|
||||||
@ -255,7 +254,7 @@ index caa0e6a34..5c2e7af02 100644
|
|||||||
@@ -86,6 +104,14 @@ class TestPkinitClientInstall(IntegrationTest):
|
@@ -86,6 +104,14 @@ class TestPkinitClientInstall(IntegrationTest):
|
||||||
cabundle = self.master.get_file_contents(paths.KDC_CA_BUNDLE_PEM)
|
cabundle = self.master.get_file_contents(paths.KDC_CA_BUNDLE_PEM)
|
||||||
client.put_file_contents(self.tmpbundle, cabundle)
|
client.put_file_contents(self.tmpbundle, cabundle)
|
||||||
|
|
||||||
+ def test_restart_krb5kdc(self):
|
+ def test_restart_krb5kdc(self):
|
||||||
+ tasks.kinit_admin(self.master)
|
+ tasks.kinit_admin(self.master)
|
||||||
+ self.enforce_password_and_otp()
|
+ self.enforce_password_and_otp()
|
||||||
@ -267,6 +266,6 @@ index caa0e6a34..5c2e7af02 100644
|
|||||||
def test_client_install_pkinit(self):
|
def test_client_install_pkinit(self):
|
||||||
tasks.kinit_admin(self.master)
|
tasks.kinit_admin(self.master)
|
||||||
self.add_certmaperule()
|
self.add_certmaperule()
|
||||||
--
|
--
|
||||||
2.43.0
|
2.43.0
|
||||||
|
|
||||||
|
@ -0,0 +1,392 @@
|
|||||||
|
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')
|
||||||
|
|
@ -0,0 +1,43 @@
|
|||||||
|
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,50 @@
|
|||||||
|
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
|
||||||
|
|
335
SOURCES/0026-backport-test-fixes_rhel#29908.patch
Normal file
335
SOURCES/0026-backport-test-fixes_rhel#29908.patch
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
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",
|
||||||
|
]
|
341
SOURCES/0027-kdb-fix-vulnerability-in-GCD-rules-handling.patch
Normal file
341
SOURCES/0027-kdb-fix-vulnerability-in-GCD-rules-handling.patch
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
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
|
||||||
|
|
@ -0,0 +1,615 @@
|
|||||||
|
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,127 @@
|
|||||||
|
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,13 @@
|
|||||||
|
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):
|
@ -0,0 +1,114 @@
|
|||||||
|
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,337 @@
|
|||||||
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
@ -0,0 +1,58 @@
|
|||||||
|
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.
|
1539
SOURCES/0034-Add-ipa-idrange-fix_rhel#56920.patch
Normal file
1539
SOURCES/0034-Add-ipa-idrange-fix_rhel#56920.patch
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,87 @@
|
|||||||
|
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
|
||||||
|
diff --git a/ipatests/test_integration/test_installation.py b/ipatests/test_integration/test_installation.py
|
||||||
|
index d41c1ee..ef0727e 100644
|
||||||
|
--- a/ipatests/test_integration/test_installation.py
|
||||||
|
+++ b/ipatests/test_integration/test_installation.py
|
||||||
|
@@ -1188,6 +1188,21 @@ class TestInstallMaster(IntegrationTest):
|
||||||
|
expected_stdout=f'href="https://{self.master.hostname}/'
|
||||||
|
)
|
||||||
|
|
||||||
|
+ def test_pac_configuration_enabled(self):
|
||||||
|
+ """
|
||||||
|
+ This testcase checks that the default PAC type
|
||||||
|
+ is added to configuration.
|
||||||
|
+ """
|
||||||
|
+ base_dn = str(self.master.domain.basedn)
|
||||||
|
+ dn = DN(
|
||||||
|
+ ("cn", "ipaConfig"),
|
||||||
|
+ ("cn", "etc"),
|
||||||
|
+ base_dn
|
||||||
|
+ )
|
||||||
|
+ result = tasks.ldapsearch_dm(self.master, str(dn),
|
||||||
|
+ ["ipaKrbAuthzData"])
|
||||||
|
+ assert 'ipaKrbAuthzData: MS-PAC' in result.stdout_text
|
||||||
|
+
|
||||||
|
def test_hostname_parameter(self, server_cleanup):
|
||||||
|
"""
|
||||||
|
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
|
||||||
|
--- a/ipatests/test_integration/test_upgrade.py
|
||||||
|
+++ b/ipatests/test_integration/test_upgrade.py
|
||||||
|
@@ -165,7 +165,6 @@ class TestUpgrade(IntegrationTest):
|
||||||
|
ldap.update_entry(location_krb_rec)
|
||||||
|
|
||||||
|
yield _setup_locations
|
||||||
|
-
|
||||||
|
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)
|
||||||
|
+
|
||||||
|
+ def test_mspac_attribute_set(self):
|
||||||
|
+ """
|
||||||
|
+ This testcase deletes the already existing attribute
|
||||||
|
+ 'ipaKrbAuthzData: MS-PAC'.
|
||||||
|
+ The test then runs ipa-server-upgrade and checks that
|
||||||
|
+ the attribute 'ipaKrbAuthzData: MS-PAC' is added again.
|
||||||
|
+ """
|
||||||
|
+ base_dn = str(self.master.domain.basedn)
|
||||||
|
+ dn = DN(
|
||||||
|
+ ("cn", "ipaConfig"),
|
||||||
|
+ ("cn", "etc"),
|
||||||
|
+ base_dn
|
||||||
|
+ )
|
||||||
|
+ ldif = textwrap.dedent("""
|
||||||
|
+ dn: cn=ipaConfig,cn=etc,{}
|
||||||
|
+ changetype: modify
|
||||||
|
+ delete: ipaKrbAuthzData
|
||||||
|
+ """).format(base_dn)
|
||||||
|
+ tasks.ldapmodify_dm(self.master, ldif)
|
||||||
|
+ tasks.kinit_admin(self.master)
|
||||||
|
+ self.master.run_command(['ipa-server-upgrade'])
|
||||||
|
+ result = tasks.ldapsearch_dm(self.master, str(dn),
|
||||||
|
+ ["ipaKrbAuthzData"])
|
||||||
|
+ assert 'ipaKrbAuthzData: MS-PAC' in result.stdout_text
|
@ -0,0 +1,72 @@
|
|||||||
|
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):
|
||||||
|
|
@ -0,0 +1,245 @@
|
|||||||
|
From 19f22cf75ae768dd2b6c0d674cf55f8d6ffafb31 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
Date: Mar 07 2025 06:48:02 +0000
|
||||||
|
Subject: Replica CA installation: ignore time skew during initial replication
|
||||||
|
|
||||||
|
|
||||||
|
During a replica CA installation, the initial replication step may fail
|
||||||
|
if there is too much time skew between the server and replica.
|
||||||
|
|
||||||
|
The replica installer already takes care of this for the replication of
|
||||||
|
the domain suffix but the replica CA installer does not set
|
||||||
|
nssldapd-ignore-time-skew to on for o=ipaca suffix.
|
||||||
|
|
||||||
|
During a replica CA installation, read the initial value of
|
||||||
|
nssldapd-ignore-time-skew, force it to on, start replication and
|
||||||
|
revert to the initial value.
|
||||||
|
|
||||||
|
Apply the same logic to dsinstance and ipa-replica-manage force-sync.
|
||||||
|
|
||||||
|
Fixes: https://pagure.io/freeipa/issue/9635
|
||||||
|
Signed-off-by: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
diff --git a/install/share/Makefile.am b/install/share/Makefile.am
|
||||||
|
index e0fe4b7..4029297 100644
|
||||||
|
--- a/install/share/Makefile.am
|
||||||
|
+++ b/install/share/Makefile.am
|
||||||
|
@@ -38,7 +38,6 @@ dist_app_DATA = \
|
||||||
|
default-trust-view.ldif \
|
||||||
|
delegation.ldif \
|
||||||
|
replica-acis.ldif \
|
||||||
|
- replica-prevent-time-skew.ldif \
|
||||||
|
ds-nfiles.ldif \
|
||||||
|
ds-ipa-env.conf.template \
|
||||||
|
dns.ldif \
|
||||||
|
diff --git a/install/share/replica-prevent-time-skew.ldif b/install/share/replica-prevent-time-skew.ldif
|
||||||
|
deleted file mode 100644
|
||||||
|
index 5d301fe..0000000
|
||||||
|
--- a/install/share/replica-prevent-time-skew.ldif
|
||||||
|
+++ /dev/null
|
||||||
|
@@ -1,4 +0,0 @@
|
||||||
|
-dn: cn=config
|
||||||
|
-changetype: modify
|
||||||
|
-replace: nsslapd-ignore-time-skew
|
||||||
|
-nsslapd-ignore-time-skew: $SKEWVALUE
|
||||||
|
diff --git a/install/tools/ipa-replica-manage.in b/install/tools/ipa-replica-manage.in
|
||||||
|
index cebf73a..71851be 100644
|
||||||
|
--- a/install/tools/ipa-replica-manage.in
|
||||||
|
+++ b/install/tools/ipa-replica-manage.in
|
||||||
|
@@ -1237,12 +1237,13 @@ def force_sync(realm, thishost, fromhost, dirman_passwd, nolookup=False):
|
||||||
|
repl.force_sync(repl.conn, fromhost)
|
||||||
|
else:
|
||||||
|
ds = dsinstance.DsInstance(realm_name=realm)
|
||||||
|
- ds.replica_manage_time_skew(prevent=False)
|
||||||
|
+ ds.replica_ignore_initial_time_skew()
|
||||||
|
repl = replication.ReplicationManager(realm, fromhost, dirman_passwd)
|
||||||
|
repl.force_sync(repl.conn, thishost)
|
||||||
|
agreement = repl.get_replication_agreement(thishost)
|
||||||
|
repl.wait_for_repl_update(repl.conn, agreement.dn)
|
||||||
|
- ds.replica_manage_time_skew(prevent=True)
|
||||||
|
+ ds.replica_revert_time_skew()
|
||||||
|
+
|
||||||
|
|
||||||
|
def show_DNA_ranges(hostname, master, realm, dirman_passwd, nextrange=False,
|
||||||
|
nolookup=False):
|
||||||
|
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
|
||||||
|
index 35cec89..e15e629 100644
|
||||||
|
--- a/ipaserver/install/cainstance.py
|
||||||
|
+++ b/ipaserver/install/cainstance.py
|
||||||
|
@@ -409,7 +409,11 @@ class CAInstance(DogtagInstance):
|
||||||
|
if promote:
|
||||||
|
# Setup Database
|
||||||
|
self.step("creating certificate server db", self.__create_ds_db)
|
||||||
|
+ self.step("ignore time skew for initial replication",
|
||||||
|
+ self.replica_ignore_initial_time_skew)
|
||||||
|
self.step("setting up initial replication", self.__setup_replication)
|
||||||
|
+ self.step("revert time skew after initial replication",
|
||||||
|
+ self.replica_revert_time_skew)
|
||||||
|
self.step("creating ACIs for admin", self.add_ipaca_aci)
|
||||||
|
self.step("creating installation admin user", self.setup_admin)
|
||||||
|
self.step("configuring certificate server instance",
|
||||||
|
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
|
||||||
|
index cbacfae..ba4bf8a 100644
|
||||||
|
--- a/ipaserver/install/dsinstance.py
|
||||||
|
+++ b/ipaserver/install/dsinstance.py
|
||||||
|
@@ -385,11 +385,11 @@ class DsInstance(service.Service):
|
||||||
|
# This helps with initial replication or force-sync because
|
||||||
|
# the receiving side has no valuable changes itself yet.
|
||||||
|
self.step("ignore time skew for initial replication",
|
||||||
|
- self.__replica_ignore_initial_time_skew)
|
||||||
|
+ self.replica_ignore_initial_time_skew)
|
||||||
|
|
||||||
|
self.step("setting up initial replication", self.__setup_replica)
|
||||||
|
self.step("prevent time skew after initial replication",
|
||||||
|
- self.replica_manage_time_skew)
|
||||||
|
+ self.replica_revert_time_skew)
|
||||||
|
self.step("adding sasl mappings to the directory", self.__configure_sasl_mappings)
|
||||||
|
self.step("updating schema", self.__update_schema)
|
||||||
|
# See LDIFs for automember configuration during replica install
|
||||||
|
@@ -995,16 +995,6 @@ class DsInstance(service.Service):
|
||||||
|
def __add_replication_acis(self):
|
||||||
|
self._ldap_mod("replica-acis.ldif", self.sub_dict)
|
||||||
|
|
||||||
|
- def __replica_ignore_initial_time_skew(self):
|
||||||
|
- self.replica_manage_time_skew(prevent=False)
|
||||||
|
-
|
||||||
|
- def replica_manage_time_skew(self, prevent=True):
|
||||||
|
- if prevent:
|
||||||
|
- self.sub_dict['SKEWVALUE'] = 'off'
|
||||||
|
- else:
|
||||||
|
- self.sub_dict['SKEWVALUE'] = 'on'
|
||||||
|
- self._ldap_mod("replica-prevent-time-skew.ldif", self.sub_dict)
|
||||||
|
-
|
||||||
|
def __setup_s4u2proxy(self):
|
||||||
|
|
||||||
|
def __add_principal(last_cn, principal, self):
|
||||||
|
diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py
|
||||||
|
index 13ae346..15ca70b 100644
|
||||||
|
--- a/ipaserver/install/service.py
|
||||||
|
+++ b/ipaserver/install/service.py
|
||||||
|
@@ -811,6 +811,31 @@ class Service:
|
||||||
|
self.run_getkeytab(self.api.env.ldap_uri, self.keytab, self.principal)
|
||||||
|
self.set_keytab_owner()
|
||||||
|
|
||||||
|
+ def replica_ignore_initial_time_skew(self):
|
||||||
|
+ """
|
||||||
|
+ Set nsslapd-ignore-time-skew = on if not already set
|
||||||
|
+ and store the initial value in order to restore it later.
|
||||||
|
+
|
||||||
|
+ The on value allows replica initialization even if there
|
||||||
|
+ are excessive time skews.
|
||||||
|
+ """
|
||||||
|
+ dn = DN(('cn', 'config'))
|
||||||
|
+ entry_attrs = api.Backend.ldap2.get_entry(dn)
|
||||||
|
+ self.original_time_skew = entry_attrs['nsslapd-ignore-time-skew'][0]
|
||||||
|
+ if self.original_time_skew != 'on':
|
||||||
|
+ entry_attrs['nsslapd-ignore-time-skew'] = 'on'
|
||||||
|
+ api.Backend.ldap2.update_entry(entry_attrs)
|
||||||
|
+
|
||||||
|
+ def replica_revert_time_skew(self):
|
||||||
|
+ """
|
||||||
|
+ Revert nsslapd-ignore-time-skew to its previous value.
|
||||||
|
+ """
|
||||||
|
+ dn = DN(('cn', 'config'))
|
||||||
|
+ entry_attrs = api.Backend.ldap2.get_entry(dn)
|
||||||
|
+ if self.original_time_skew != 'on':
|
||||||
|
+ entry_attrs['nsslapd-ignore-time-skew'] = self.original_time_skew
|
||||||
|
+ api.Backend.ldap2.update_entry(entry_attrs)
|
||||||
|
+
|
||||||
|
|
||||||
|
class SimpleServiceInstance(Service):
|
||||||
|
def create_instance(self, gensvc_name=None, fqdn=None, ldap_suffix=None,
|
||||||
|
|
||||||
|
From a6bb2fa4997dd7894dbf75d1c3fd1deaebd3e05c Mon Sep 17 00:00:00 2001
|
||||||
|
From: Sudhir Menon <sumenon@redhat.com>
|
||||||
|
Date: Mar 07 2025 06:48:02 +0000
|
||||||
|
Subject: ipatests: Test to check that the configured value for "nsslapd-ignore-time-skew" remains on even after a "force-sync" is done
|
||||||
|
|
||||||
|
|
||||||
|
Related: https://pagure.io/freeipa/issue/9635
|
||||||
|
|
||||||
|
Signed-off-by: Sudhir Menon <sumenon@redhat.com>
|
||||||
|
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
diff --git a/ipatests/test_integration/test_installation.py b/ipatests/test_integration/test_installation.py
|
||||||
|
index ef0727e..3673f7f 100644
|
||||||
|
--- a/ipatests/test_integration/test_installation.py
|
||||||
|
+++ b/ipatests/test_integration/test_installation.py
|
||||||
|
@@ -2132,3 +2132,69 @@ class TestHostnameValidator(IntegrationTest):
|
||||||
|
assert result.returncode == 1
|
||||||
|
assert 'hostname cannot be the same as the domain name' \
|
||||||
|
in result.stderr_text
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+class TestNsslapdIgnoreTimeSkew(IntegrationTest):
|
||||||
|
+ """
|
||||||
|
+ Test to check nsslapd-ignore-time-skew is not disabled.
|
||||||
|
+ """
|
||||||
|
+ num_replicas = 1
|
||||||
|
+ topology = 'line'
|
||||||
|
+
|
||||||
|
+ @pytest.fixture
|
||||||
|
+ def update_time_skew(self):
|
||||||
|
+ """
|
||||||
|
+ Fixture enables nsslapd-ignore-time-skew
|
||||||
|
+ parameter and reverts it back
|
||||||
|
+ """
|
||||||
|
+ ldap = self.replicas[0].ldap_connect()
|
||||||
|
+ dn = DN(
|
||||||
|
+ ("cn", "config"),
|
||||||
|
+ )
|
||||||
|
+ entry = ldap.get_entry(dn)
|
||||||
|
+ entry.single_value["nsslapd-ignore-time-skew"] = 'on'
|
||||||
|
+ ldap.update_entry(entry)
|
||||||
|
+
|
||||||
|
+ yield
|
||||||
|
+
|
||||||
|
+ entry = ldap.get_entry(dn)
|
||||||
|
+ entry.single_value["nsslapd-ignore-time-skew"] = 'off'
|
||||||
|
+ ldap.update_entry(entry)
|
||||||
|
+
|
||||||
|
+ def test_check_nsslapd_ignore_time_skew(self):
|
||||||
|
+ """
|
||||||
|
+ This testcase checks that the ignore time skew parameter
|
||||||
|
+ is set to on during the directory server replica
|
||||||
|
+ installation (replication of the suffix) and during
|
||||||
|
+ the CA replica (replication of o=ipaca).
|
||||||
|
+ It also checks that the time skew is reverted during
|
||||||
|
+ pki_tomcat setup stage.
|
||||||
|
+ """
|
||||||
|
+ DIRSRV_LOG = (
|
||||||
|
+ "ignore time skew for initial replication"
|
||||||
|
+ )
|
||||||
|
+ PKI_TOMCAT_LOG = (
|
||||||
|
+ "revert time skew after initial replication"
|
||||||
|
+ )
|
||||||
|
+ install_msg = self.replicas[0].get_file_contents(
|
||||||
|
+ paths.IPAREPLICA_INSTALL_LOG, encoding="utf-8"
|
||||||
|
+ )
|
||||||
|
+ dirsrv_msg = re.findall(DIRSRV_LOG, install_msg)
|
||||||
|
+ assert len(dirsrv_msg) == 2
|
||||||
|
+ assert PKI_TOMCAT_LOG in install_msg
|
||||||
|
+
|
||||||
|
+ def test_forcesync_does_not_overwrite_ignore_time_skew(
|
||||||
|
+ self, update_time_skew):
|
||||||
|
+ """
|
||||||
|
+ This testcase checks that calling ipa-replica-manage
|
||||||
|
+ force-sync does not overwrite the value of ignore
|
||||||
|
+ time skew
|
||||||
|
+ """
|
||||||
|
+ result = self.replicas[0].run_command(
|
||||||
|
+ ["ipa-replica-manage", "force-sync",
|
||||||
|
+ "--from", self.master.hostname,
|
||||||
|
+ "--no-lookup", "-v"])
|
||||||
|
+ assert result.returncode == 0
|
||||||
|
+ conn = self.replicas[0].ldap_connect()
|
||||||
|
+ ldap_entry = conn.get_entry(DN("cn=config"))
|
||||||
|
+ assert ldap_entry.single_value['nsslapd-ignore-time-skew'] == "on"
|
||||||
|
|
@ -0,0 +1,82 @@
|
|||||||
|
From ac6eee670d8a753e66ba69a65eff55447fff2822 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aleksandr Sharov <asharov@redhat.com>
|
||||||
|
Date: Mar 25 2025 09:33:06 +0000
|
||||||
|
Subject: Add a check into ipa-cert-fix tool to avoid updating certs if CA is close to being expired.
|
||||||
|
|
||||||
|
|
||||||
|
Fixes: https://pagure.io/freeipa/issue/9760
|
||||||
|
Signed-off-by: Aleksandr Sharov <asharov@redhat.com>
|
||||||
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
diff --git a/ipaserver/install/ipa_cert_fix.py b/ipaserver/install/ipa_cert_fix.py
|
||||||
|
index 8e02d1e..960d7b9 100644
|
||||||
|
--- a/ipaserver/install/ipa_cert_fix.py
|
||||||
|
+++ b/ipaserver/install/ipa_cert_fix.py
|
||||||
|
@@ -69,6 +69,7 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
cert_nicknames = {
|
||||||
|
+ 'ca_issuing': 'caSigningCert cert-pki-ca',
|
||||||
|
'sslserver': 'Server-Cert cert-pki-ca',
|
||||||
|
'subsystem': 'subsystemCert cert-pki-ca',
|
||||||
|
'ca_ocsp_signing': 'ocspSigningCert cert-pki-ca',
|
||||||
|
@@ -137,6 +138,16 @@ class IPACertFix(AdminTool):
|
||||||
|
print("Nothing to do.")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
+ if any(key == 'ca_issuing' for key, _ in certs):
|
||||||
|
+ logger.debug("CA signing cert is expired, exiting!")
|
||||||
|
+ print(
|
||||||
|
+ "The CA signing certificate is expired or will expire within "
|
||||||
|
+ "the next two weeks.\n\nipa-cert-fix cannot proceed, please "
|
||||||
|
+ "refer to the ipa-cacert-manage tool to renew the CA "
|
||||||
|
+ "certificate before proceeding."
|
||||||
|
+ )
|
||||||
|
+ return 1
|
||||||
|
+
|
||||||
|
print(msg)
|
||||||
|
|
||||||
|
print_intentions(certs, extra_certs, non_renewed)
|
||||||
|
|
||||||
|
From cdc03d7b6233f736c51c10aa07225aac9715e4c0 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aleksandr Sharov <asharov@redhat.com>
|
||||||
|
Date: Mar 25 2025 18:03:54 +0000
|
||||||
|
Subject: Test fix for the update
|
||||||
|
|
||||||
|
|
||||||
|
Fixes: https://pagure.io/freeipa/issue/9760
|
||||||
|
Signed-off-by: Aleksandr Sharov <asharov@redhat.com>
|
||||||
|
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
|
||||||
|
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
diff --git a/ipatests/test_integration/test_ipa_cert_fix.py b/ipatests/test_integration/test_ipa_cert_fix.py
|
||||||
|
index 15d8a81..d11fd3d 100644
|
||||||
|
--- a/ipatests/test_integration/test_ipa_cert_fix.py
|
||||||
|
+++ b/ipatests/test_integration/test_ipa_cert_fix.py
|
||||||
|
@@ -301,13 +301,18 @@ class TestIpaCertFix(IntegrationTest):
|
||||||
|
valid. If CA cert expired, ipa-cert-fix won't work.
|
||||||
|
|
||||||
|
related: https://pagure.io/freeipa/issue/8721
|
||||||
|
+
|
||||||
|
+ If CA cert is close to expiry, there's no reason to issue new certs
|
||||||
|
+ with short validity period. So, ipa-cert-fix should fail in this case.
|
||||||
|
+
|
||||||
|
+ related: https://pagure.io/freeipa/issue/9760
|
||||||
|
"""
|
||||||
|
result = self.master.run_command(['ipa-cert-fix', '-v'],
|
||||||
|
stdin_text='yes\n',
|
||||||
|
raiseonerr=False)
|
||||||
|
# check that pki-server cert-fix command fails
|
||||||
|
- err_msg = ("ERROR: CalledProcessError(Command "
|
||||||
|
- "['pki-server', 'cert-fix'")
|
||||||
|
+ err_msg = ("CA signing cert is expired, exiting!")
|
||||||
|
+ assert result.returncode == 1
|
||||||
|
assert err_msg in result.stderr_text
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -32,7 +32,7 @@ diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py
|
|||||||
index 7d21367ec..42a47f1df 100644
|
index 7d21367ec..42a47f1df 100644
|
||||||
--- a/ipaplatform/base/paths.py
|
--- a/ipaplatform/base/paths.py
|
||||||
+++ b/ipaplatform/base/paths.py
|
+++ b/ipaplatform/base/paths.py
|
||||||
@@ -259,7 +259,6 @@ class BasePathNamespace:
|
@@ -258,8 +258,7 @@ class BasePathNamespace:
|
||||||
IPA_PKI_RETRIEVE_KEY = "/usr/libexec/ipa/ipa-pki-retrieve-key"
|
IPA_PKI_RETRIEVE_KEY = "/usr/libexec/ipa/ipa-pki-retrieve-key"
|
||||||
IPA_HTTPD_PASSWD_READER = "/usr/libexec/ipa/ipa-httpd-pwdreader"
|
IPA_HTTPD_PASSWD_READER = "/usr/libexec/ipa/ipa-httpd-pwdreader"
|
||||||
IPA_PKI_WAIT_RUNNING = "/usr/libexec/ipa/ipa-pki-wait-running"
|
IPA_PKI_WAIT_RUNNING = "/usr/libexec/ipa/ipa-pki-wait-running"
|
||||||
@ -41,6 +41,7 @@ index 7d21367ec..42a47f1df 100644
|
|||||||
- DNSSEC_KEYFROMLABEL_9_17 = "/usr/bin/dnssec-keyfromlabel"
|
- DNSSEC_KEYFROMLABEL_9_17 = "/usr/bin/dnssec-keyfromlabel"
|
||||||
GETSEBOOL = "/usr/sbin/getsebool"
|
GETSEBOOL = "/usr/sbin/getsebool"
|
||||||
GROUPADD = "/usr/sbin/groupadd"
|
GROUPADD = "/usr/sbin/groupadd"
|
||||||
|
USERMOD = "/usr/sbin/usermod"
|
||||||
diff --git a/ipaplatform/fedora/paths.py b/ipaplatform/fedora/paths.py
|
diff --git a/ipaplatform/fedora/paths.py b/ipaplatform/fedora/paths.py
|
||||||
index 4e993c063..92a948966 100644
|
index 4e993c063..92a948966 100644
|
||||||
--- a/ipaplatform/fedora/paths.py
|
--- a/ipaplatform/fedora/paths.py
|
||||||
|
@ -81,7 +81,8 @@
|
|||||||
|
|
||||||
# Fix for TLS 1.3 PHA, RHBZ#1775158
|
# Fix for TLS 1.3 PHA, RHBZ#1775158
|
||||||
%global httpd_version 2.4.37-21
|
%global httpd_version 2.4.37-21
|
||||||
%global bind_version 9.11.20-6
|
# Fix for RHEL-25649
|
||||||
|
%global bind_version 9.11.36-14
|
||||||
|
|
||||||
%else
|
%else
|
||||||
# Fedora
|
# Fedora
|
||||||
@ -189,7 +190,7 @@
|
|||||||
|
|
||||||
Name: %{package_name}
|
Name: %{package_name}
|
||||||
Version: %{IPA_VERSION}
|
Version: %{IPA_VERSION}
|
||||||
Release: 7%{?rc_version:.%rc_version}%{?dist}
|
Release: 16%{?rc_version:.%rc_version}%{?dist}
|
||||||
Summary: The Identity, Policy and Audit system
|
Summary: The Identity, Policy and Audit system
|
||||||
|
|
||||||
License: GPLv3+
|
License: GPLv3+
|
||||||
@ -230,6 +231,22 @@ Patch0019: 0019-Vault-add-support-for-RSA-OAEP-wrapping-algo.patch
|
|||||||
Patch0020: 0020-Vault-improve-vault-server-archival-retrieval-calls-.patch
|
Patch0020: 0020-Vault-improve-vault-server-archival-retrieval-calls-.patch
|
||||||
Patch0021: 0021-kra-set-RSA-OAEP-as-default-wrapping-algo-when-FIPS-.patch
|
Patch0021: 0021-kra-set-RSA-OAEP-as-default-wrapping-algo-when-FIPS-.patch
|
||||||
Patch0022: 0022-ipa-kdb-Fix-double-free-in-ipadb_reinit_mspac.patch
|
Patch0022: 0022-ipa-kdb-Fix-double-free-in-ipadb_reinit_mspac.patch
|
||||||
|
Patch0023: 0023-rpcserver-validate-Kerberos-principal-name-before-running-kinit_rhel#26153.patch
|
||||||
|
Patch0024: 0024-Vault-add-additional-fallback-to-RSA-OAEP-wrapping-algo_rhel#28259.patch
|
||||||
|
Patch0025: 0025-dcerpc-invalidate-forest-trust-intfo-cache-when-filtering-out-realm-domains_rhel#28559.patch
|
||||||
|
Patch0026: 0026-backport-test-fixes_rhel#29908.patch
|
||||||
|
Patch0027: 0027-kdb-fix-vulnerability-in-GCD-rules-handling.patch
|
||||||
|
Patch0028: 0028-kdb-apply-combinatorial-logic-for-ticket-flags.patch
|
||||||
|
Patch0029: 0029-Allow_the_admin_user_to_be_disabled_rhel#34756.patch
|
||||||
|
Patch0030: 0030-ipa-otptoken-import-open-the-key-file-in-binary-mode_rhel#39616.patch
|
||||||
|
Patch0031: 0031-ipa-crlgen-manage-manage-the-cert-status-task-execution-time_rhel#30280.patch
|
||||||
|
Patch0032: 0032-idrange-add-add-a-warning-because-389ds-restart-is-required_rhel#28996.patch
|
||||||
|
Patch0033: 0033-PKINIT-certificate-fix-renewal-on-hidden-replica_rhel#4913.patch
|
||||||
|
Patch0034: 0034-Add-ipa-idrange-fix_rhel#56920.patch
|
||||||
|
Patch0035: 0035-Unconditionally-add-MS-PAC-to-global-config-on-update_rhel#49437.patch
|
||||||
|
Patch0036: 0036-ipatests-Update-ipa-adtrust-install-test_rhel#40894.patch
|
||||||
|
Patch0037: 0037-Replica-CA-installation-ignore-skew-during-initial-replication_rhel#80995.patch
|
||||||
|
Patch0038: 0038-Add-a-check-into-ipa-cert-fix-tool-to-avoid-updating-certs-if-CA-is-close-to-being-expired_rhel#4941.patch
|
||||||
%if 0%{?rhel} >= 8
|
%if 0%{?rhel} >= 8
|
||||||
Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch
|
Patch1001: 1001-Change-branding-to-IPA-and-Identity-Management.patch
|
||||||
Patch1002: 1002-Revert-freeipa.spec-depend-on-bind-dnssec-utils.patch
|
Patch1002: 1002-Revert-freeipa.spec-depend-on-bind-dnssec-utils.patch
|
||||||
@ -390,7 +407,7 @@ BuildRequires: python3-pycodestyle
|
|||||||
BuildRequires: python3-pylint
|
BuildRequires: python3-pylint
|
||||||
BuildRequires: python3-pytest-multihost
|
BuildRequires: python3-pytest-multihost
|
||||||
BuildRequires: python3-pytest-sourceorder
|
BuildRequires: python3-pytest-sourceorder
|
||||||
BuildRequires: python3-qrcode-core >= 5.0.0
|
BuildRequires: python3-qrcode-core >= 5.3
|
||||||
BuildRequires: python3-samba
|
BuildRequires: python3-samba
|
||||||
BuildRequires: python3-six
|
BuildRequires: python3-six
|
||||||
BuildRequires: python3-sss
|
BuildRequires: python3-sss
|
||||||
@ -993,10 +1010,7 @@ for i in *.po ; do
|
|||||||
done
|
done
|
||||||
popd
|
popd
|
||||||
|
|
||||||
for p in %patches ; do
|
%autopatch -p1
|
||||||
%__patch -p1 -i $p
|
|
||||||
UpdateTimestamps -p1 $p
|
|
||||||
done
|
|
||||||
|
|
||||||
%build
|
%build
|
||||||
# PATH is workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1005235
|
# PATH is workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1005235
|
||||||
@ -1391,6 +1405,7 @@ fi
|
|||||||
%{_sbindir}/ipa-pkinit-manage
|
%{_sbindir}/ipa-pkinit-manage
|
||||||
%{_sbindir}/ipa-crlgen-manage
|
%{_sbindir}/ipa-crlgen-manage
|
||||||
%{_sbindir}/ipa-cert-fix
|
%{_sbindir}/ipa-cert-fix
|
||||||
|
%{_sbindir}/ipa-idrange-fix
|
||||||
%{_sbindir}/ipa-acme-manage
|
%{_sbindir}/ipa-acme-manage
|
||||||
%{_libexecdir}/certmonger/dogtag-ipa-ca-renew-agent-submit
|
%{_libexecdir}/certmonger/dogtag-ipa-ca-renew-agent-submit
|
||||||
%{_libexecdir}/certmonger/ipa-server-guard
|
%{_libexecdir}/certmonger/ipa-server-guard
|
||||||
@ -1465,6 +1480,7 @@ fi
|
|||||||
%{_mandir}/man1/ipa-pkinit-manage.1*
|
%{_mandir}/man1/ipa-pkinit-manage.1*
|
||||||
%{_mandir}/man1/ipa-crlgen-manage.1*
|
%{_mandir}/man1/ipa-crlgen-manage.1*
|
||||||
%{_mandir}/man1/ipa-cert-fix.1*
|
%{_mandir}/man1/ipa-cert-fix.1*
|
||||||
|
%{_mandir}/man1/ipa-idrange-fix.1*
|
||||||
%{_mandir}/man1/ipa-acme-manage.1*
|
%{_mandir}/man1/ipa-acme-manage.1*
|
||||||
|
|
||||||
|
|
||||||
@ -1745,6 +1761,69 @@ fi
|
|||||||
%endif
|
%endif
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Mon Mar 31 2025 Rafael Jeffman <rjeffman@redhat.com> - 4.9.13-16
|
||||||
|
- Add a- heck into ipa-cert-fix tool to avoid updating certs if CA is close to expire
|
||||||
|
Resolves: RHEL-4941
|
||||||
|
- Fix rpminspect's 'patches' warnings
|
||||||
|
Resolves: RHEL-22497
|
||||||
|
|
||||||
|
* Mon Mar 10 2025 Rafael Jeffman <rjeffman@redhat.com> - 4.9.13-15
|
||||||
|
- Replica CA installation: ignore skew during initial replication
|
||||||
|
Resolves RHEL-80995
|
||||||
|
|
||||||
|
* Wed Nov 27 2024 Rafael Jeffman <rjeffman@redhat.com> - 4.9.13-14
|
||||||
|
- ipatests: Update ipa-adtrust-install test
|
||||||
|
Resolves: RHEL-40894
|
||||||
|
|
||||||
|
* Thu Nov 14 2024 Rafael Jeffman <rjeffman@redhat.com> - 4.9.13-13
|
||||||
|
- Add ipa-idrange-fix
|
||||||
|
Resolves: RHEL-56920
|
||||||
|
- Unconditionally add MS-PAC to global config on update
|
||||||
|
Resolves: RHEL-49437
|
||||||
|
- ipatests: Update ipa-adtrust-install test
|
||||||
|
Resolves: RHEL-40894
|
||||||
|
- Require python-qrcode version 5.3 or later
|
||||||
|
Related: RHEL-15090
|
||||||
|
|
||||||
|
* Wed Jul 17 2024 Rafael Jeffman <rjeffman@redhat.com> - 4.9.13-12
|
||||||
|
- Allow the admin user to be disabled
|
||||||
|
Resolves: RHEL-34756
|
||||||
|
- ipa-otptoken-import: open the key file in binary mode
|
||||||
|
Resolves: RHEL-39616
|
||||||
|
- ipa-crlgen-manage: manage the cert status task execution time
|
||||||
|
Resolves: RHEL-30280
|
||||||
|
- idrange-add: add a warning because 389ds restart is required
|
||||||
|
Resolves: RHEL-28996
|
||||||
|
- PKINIT certificate: fix renewal on hidden replica
|
||||||
|
Resolves: RHEL-4913, RHEL-45908
|
||||||
|
|
||||||
|
* Wed Jun 12 2024 Julien Rische <jrische@redhat.com> - 4.9.13-11
|
||||||
|
- Add missing part of backported CVE-2024-3183 fix
|
||||||
|
Resolves: RHEL-29927
|
||||||
|
|
||||||
|
* Tue Apr 30 2024 Julien Rische <jrische@redhat.com> - 4.9.13-10
|
||||||
|
- kdb: apply combinatorial logic for ticket flags (CVE-2024-3183)
|
||||||
|
Resolves: RHEL-29927
|
||||||
|
- kdb: fix vulnerability in GCD rules handling (CVE-2024-2698)
|
||||||
|
Resolves: RHEL-29692
|
||||||
|
|
||||||
|
* Fri Apr 12 2024 Rafael Jeffman <rjeffman@redhat.com> - 9.4.13-9
|
||||||
|
- dcerpc: invalidate forest trust intfo cache when filtering out realm domains
|
||||||
|
Resolves: RHEL-28559
|
||||||
|
- Backport latests test fixes in python3-tests
|
||||||
|
ipatests: add xfail for autoprivate group test with override
|
||||||
|
ipatests: remove xfail thanks to sssd 2.9.4
|
||||||
|
ipatests: adapt for new automembership fixup behavior
|
||||||
|
ipatests: Fixes for test_ipahealthcheck_ipansschainvalidation testcases
|
||||||
|
test_xmlrpc: adopt to automember plugin message changes in 389-ds
|
||||||
|
Resolves: RHEL-29908
|
||||||
|
|
||||||
|
* Thu Mar 07 2024 Rafael Jeffman <rjeffman@redhat.com> - 4.9.13-8
|
||||||
|
- rpcserver: validate Kerberos principal name before running kinit
|
||||||
|
Resolves: RHEL-26153
|
||||||
|
- Vault: add additional fallback to RSA-OAEP wrapping algo
|
||||||
|
Resolves: RHEL-28259
|
||||||
|
|
||||||
* Tue Feb 20 2024 Julien Rische <jrische@redhat.com> - 4.9.13-7
|
* Tue Feb 20 2024 Julien Rische <jrische@redhat.com> - 4.9.13-7
|
||||||
- ipa-kdb: Fix double free in ipadb_reinit_mspac()
|
- ipa-kdb: Fix double free in ipadb_reinit_mspac()
|
||||||
Resolves: RHEL-25742
|
Resolves: RHEL-25742
|
||||||
@ -1854,7 +1933,7 @@ fi
|
|||||||
|
|
||||||
* Thu May 25 2023 Rafael Jeffman <rjeffman@redhat.com> - 4.9.12-2
|
* Thu May 25 2023 Rafael Jeffman <rjeffman@redhat.com> - 4.9.12-2
|
||||||
- Use the OpenSSL certificate parser in cert-find
|
- Use the OpenSSL certificate parser in cert-find
|
||||||
Resolves: RHBZ#2209947
|
Resolves: RHBZ#2209947
|
||||||
|
|
||||||
* Wed May 24 2023 Rafael Jeffman <rjeffman@redhat.com> - 4.9.12-1
|
* Wed May 24 2023 Rafael Jeffman <rjeffman@redhat.com> - 4.9.12-1
|
||||||
- Rebase ipa to 4.9.12
|
- Rebase ipa to 4.9.12
|
||||||
@ -1887,7 +1966,7 @@ fi
|
|||||||
Resolves: RHBZ#2129895
|
Resolves: RHBZ#2129895
|
||||||
- Fix canonicalization issue in Web UI
|
- Fix canonicalization issue in Web UI
|
||||||
Resolves: RHBZ#2127035
|
Resolves: RHBZ#2127035
|
||||||
- Remove idnssoaserial argument from dns zone API.
|
- Remove idnssoaserial argument from dns zone API.
|
||||||
Resolves: RHBZ#2108630
|
Resolves: RHBZ#2108630
|
||||||
- Warn for permissions with read/write/search/compare and no attrs
|
- Warn for permissions with read/write/search/compare and no attrs
|
||||||
Resolves: RHBZ#2098187
|
Resolves: RHBZ#2098187
|
||||||
|
Loading…
Reference in New Issue
Block a user