Import from CS git
This commit is contained in:
parent
aec2a644bb
commit
c4b216be73
@ -1,4 +1,4 @@
|
|||||||
From 70d23b8f6bbcabe2eb621ffa5009866b43e5570a Mon Sep 17 00:00:00 2001
|
From 542e12325afc2f64298f90296760235bfdcef04a Mon Sep 17 00:00:00 2001
|
||||||
From: Julien Rische <jrische@redhat.com>
|
From: Julien Rische <jrische@redhat.com>
|
||||||
Date: Mon, 25 Mar 2024 18:25:52 +0200
|
Date: Mon, 25 Mar 2024 18:25:52 +0200
|
||||||
Subject: [PATCH] kdb: apply combinatorial logic for ticket flags
|
Subject: [PATCH] kdb: apply combinatorial logic for ticket flags
|
||||||
@ -44,15 +44,21 @@ flags like -allow_svr for a user principal by setting the
|
|||||||
case, any ticket flag can be configured in the principal ticket policy,
|
case, any ticket flag can be configured in the principal ticket policy,
|
||||||
except requires_preauth and allow_tix.
|
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
|
This fixes CVE-2024-3183
|
||||||
|
|
||||||
Signed-off-by: Julien Rische <jrische@redhat.com>
|
Signed-off-by: Julien Rische <jrische@redhat.com>
|
||||||
---
|
---
|
||||||
daemons/ipa-kdb/ipa_kdb.h | 43 ++++
|
daemons/ipa-kdb/ipa_kdb.h | 43 ++++
|
||||||
daemons/ipa-kdb/ipa_kdb_principals.c | 306 ++++++++++++++++++++++-----
|
daemons/ipa-kdb/ipa_kdb_principals.c | 353 +++++++++++++++++++++++----
|
||||||
util/ipa_krb5.c | 18 ++
|
util/ipa_krb5.c | 18 ++
|
||||||
util/ipa_krb5.h | 4 +
|
util/ipa_krb5.h | 4 +
|
||||||
4 files changed, 319 insertions(+), 52 deletions(-)
|
4 files changed, 365 insertions(+), 53 deletions(-)
|
||||||
|
|
||||||
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
|
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
|
||||||
index 7baf4697f..85cabe142 100644
|
index 7baf4697f..85cabe142 100644
|
||||||
@ -116,10 +122,10 @@ index 7baf4697f..85cabe142 100644
|
|||||||
int ipadb_get_connection(struct ipadb_context *ipactx);
|
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
|
diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c
|
||||||
index 07cc87746..cb18861bb 100644
|
index 07cc87746..6eb542d4f 100644
|
||||||
--- a/daemons/ipa-kdb/ipa_kdb_principals.c
|
--- a/daemons/ipa-kdb/ipa_kdb_principals.c
|
||||||
+++ b/daemons/ipa-kdb/ipa_kdb_principals.c
|
+++ b/daemons/ipa-kdb/ipa_kdb_principals.c
|
||||||
@@ -706,9 +706,10 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
|
@@ -706,9 +706,12 @@ static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
|
||||||
"krbTicketFlags", &result);
|
"krbTicketFlags", &result);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
entry->attributes = result;
|
entry->attributes = result;
|
||||||
@ -127,12 +133,28 @@ index 07cc87746..cb18861bb 100644
|
|||||||
- *polmask |= TKTFLAGS_BIT;
|
- *polmask |= TKTFLAGS_BIT;
|
||||||
}
|
}
|
||||||
+ /* Since principal, global policy, and virtual ticket flags are combined,
|
+ /* Since principal, global policy, and virtual ticket flags are combined,
|
||||||
+ * they must always be resolved. */
|
+ * they must always be resolved, except if we are in IPA setup mode (because
|
||||||
+ *polmask |= TKTFLAGS_BIT;
|
+ * 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,
|
ret = ipadb_ldap_attr_to_int(lcontext, lentry,
|
||||||
"krbMaxTicketLife", &result);
|
"krbMaxTicketLife", &result);
|
||||||
@@ -1251,23 +1252,150 @@ done:
|
@@ -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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,8 +184,10 @@ index 07cc87746..cb18861bb 100644
|
|||||||
+ if (!ied->ipa_user) {
|
+ if (!ied->ipa_user) {
|
||||||
+ kerr = 0;
|
+ kerr = 0;
|
||||||
+ goto end;
|
+ goto end;
|
||||||
+ }
|
}
|
||||||
+
|
|
||||||
|
- /* By default require preauth for all principals */
|
||||||
|
- return KRB5_KDB_REQUIRES_PRE_AUTH;
|
||||||
+ kerr = krb5_dbe_get_string(ipactx->kcontext, entry,
|
+ kerr = krb5_dbe_get_string(ipactx->kcontext, entry,
|
||||||
+ IPA_KDB_STRATTR_FINAL_USER_TKTFLAGS, &str);
|
+ IPA_KDB_STRATTR_FINAL_USER_TKTFLAGS, &str);
|
||||||
+ if (kerr)
|
+ if (kerr)
|
||||||
@ -208,10 +232,8 @@ index 07cc87746..cb18861bb 100644
|
|||||||
+ gcfg = ipadb_get_global_config(ipactx);
|
+ gcfg = ipadb_get_global_config(ipactx);
|
||||||
+ if (gcfg && gcfg->disable_preauth_for_spns)
|
+ if (gcfg && gcfg->disable_preauth_for_spns)
|
||||||
+ vsflg &= ~KRB5_KDB_REQUIRES_PRE_AUTH;
|
+ vsflg &= ~KRB5_KDB_REQUIRES_PRE_AUTH;
|
||||||
}
|
+ }
|
||||||
|
+
|
||||||
- /* By default require preauth for all principals */
|
|
||||||
- return KRB5_KDB_REQUIRES_PRE_AUTH;
|
|
||||||
+ if (tktflags)
|
+ if (tktflags)
|
||||||
+ *tktflags |= vsflg;
|
+ *tktflags |= vsflg;
|
||||||
+
|
+
|
||||||
@ -295,7 +317,7 @@ index 07cc87746..cb18861bb 100644
|
|||||||
}
|
}
|
||||||
|
|
||||||
static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
|
static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
|
||||||
@@ -1280,6 +1408,7 @@ 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;
|
char *policy_dn = NULL;
|
||||||
LDAPMessage *res = NULL;
|
LDAPMessage *res = NULL;
|
||||||
LDAPMessage *first;
|
LDAPMessage *first;
|
||||||
@ -303,7 +325,7 @@ index 07cc87746..cb18861bb 100644
|
|||||||
int result;
|
int result;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -1288,12 +1417,18 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
|
@@ -1288,12 +1424,18 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
|
||||||
return KRB5_KDB_DBNOTINITED;
|
return KRB5_KDB_DBNOTINITED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,7 +344,7 @@ index 07cc87746..cb18861bb 100644
|
|||||||
ret = asprintf(&policy_dn, "cn=%s,cn=kerberos,%s",
|
ret = asprintf(&policy_dn, "cn=%s,cn=kerberos,%s",
|
||||||
ipactx->realm, ipactx->base);
|
ipactx->realm, ipactx->base);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
@@ -1337,12 +1472,13 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
|
@@ -1337,12 +1479,13 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (polmask & TKTFLAGS_BIT) {
|
if (polmask & TKTFLAGS_BIT) {
|
||||||
@ -342,7 +364,7 @@ index 07cc87746..cb18861bb 100644
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1366,13 +1502,27 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
|
@@ -1366,13 +1509,27 @@ static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
|
||||||
if (polmask & MAXRENEWABLEAGE_BIT) {
|
if (polmask & MAXRENEWABLEAGE_BIT) {
|
||||||
entry->max_renewable_life = 604800;
|
entry->max_renewable_life = 604800;
|
||||||
}
|
}
|
||||||
@ -373,7 +395,44 @@ index 07cc87746..cb18861bb 100644
|
|||||||
done:
|
done:
|
||||||
ldap_msgfree(res);
|
ldap_msgfree(res);
|
||||||
free(policy_dn);
|
free(policy_dn);
|
||||||
@@ -2275,6 +2425,85 @@ static krb5_error_code ipadb_get_ldap_mod_auth_ind(krb5_context kcontext,
|
@@ -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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,70 +447,78 @@ index 07cc87746..cb18861bb 100644
|
|||||||
+ krb5_flags tktflags_mask;
|
+ krb5_flags tktflags_mask;
|
||||||
+ int tktflags;
|
+ int tktflags;
|
||||||
+
|
+
|
||||||
+ kerr = ipadb_get_edata(entry, &ied);
|
|
||||||
+ if (kerr)
|
|
||||||
+ goto end;
|
|
||||||
+
|
|
||||||
+ ipactx = ipadb_get_context(kcontext);
|
+ ipactx = ipadb_get_context(kcontext);
|
||||||
+ if (!ipactx) {
|
+ if (!ipactx) {
|
||||||
+ kerr = KRB5_KDB_DBNOTINITED;
|
+ kerr = KRB5_KDB_DBNOTINITED;
|
||||||
+ goto end;
|
+ goto end;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ kerr = get_virtual_static_tktflags_mask(ipactx, entry, &tktflags_mask);
|
+ if (ipactx->override_restrictions) {
|
||||||
+ if (kerr)
|
+ /* In IPA setup mode, IPA edata might not be available. In this mode,
|
||||||
+ goto end;
|
+ * ticket flags are written as they are provided. */
|
||||||
+
|
+ tktflags = (int)entry->attributes;
|
||||||
+ kerr = are_final_tktflags(ipactx, entry, &final_tktflags);
|
+ } else {
|
||||||
+ if (kerr)
|
+ kerr = ipadb_get_edata(entry, &ied);
|
||||||
+ 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 gtpol_tktflags = 0;
|
|
||||||
+
|
|
||||||
+ kerr = add_global_ticket_policy_flags(ipactx, NULL, >pol_tktflags);
|
|
||||||
+ if (kerr)
|
+ if (kerr)
|
||||||
+ goto end;
|
+ goto end;
|
||||||
+
|
+
|
||||||
+ tktflags_mask &= ~gtpol_tktflags;
|
+ kerr = get_virtual_static_tktflags_mask(ipactx, entry, &tktflags_mask);
|
||||||
+ }
|
+ if (kerr)
|
||||||
+
|
|
||||||
+ tktflags = (int)(entry->attributes & tktflags_mask);
|
|
||||||
+
|
|
||||||
+ if (LDAP_MOD_REPLACE == mod_op && !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;
|
+ 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;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ /* if the object does not have the krbTicketPolicyAux class
|
+ tktflags = (int)(entry->attributes & tktflags_mask);
|
||||||
+ * we need to add it or this will fail, only for modifications.
|
+
|
||||||
+ * We always add this objectclass by default when doing an add
|
+ if (LDAP_MOD_REPLACE == mod_op && ied && !ied->has_tktpolaux) {
|
||||||
+ * from scratch. */
|
+ if (0 == tktflags) {
|
||||||
+ kerr = ipadb_get_ldap_mod_str(imods, "objectclass",
|
+ /* No point initializing principal ticket policy if there are no
|
||||||
+ "krbTicketPolicyAux", LDAP_MOD_ADD);
|
+ * flags left after filtering out virtual and global ticket
|
||||||
+ if (kerr)
|
+ * policy ones. */
|
||||||
+ goto end;
|
+ 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;
|
||||||
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ kerr = ipadb_get_ldap_mod_int(imods, "krbTicketFlags", tktflags, mod_op);
|
+ if (tktflags != 0) {
|
||||||
+ if (kerr)
|
|
||||||
+ goto end;
|
|
||||||
+
|
|
||||||
+ /* If there are no custom ticket flags set in the principal, remove the
|
|
||||||
+ * "krbTicketFlags" attribute. */
|
|
||||||
+ if (0 == tktflags) {
|
|
||||||
+ kerr = ipadb_get_ldap_mod_int(imods, "krbTicketFlags", tktflags,
|
+ kerr = ipadb_get_ldap_mod_int(imods, "krbTicketFlags", tktflags,
|
||||||
+ LDAP_MOD_DELETE);
|
+ 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)
|
+ if (kerr)
|
||||||
+ goto end;
|
+ goto end;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
|
+ kerr = 0;
|
||||||
|
+
|
||||||
+end:
|
+end:
|
||||||
+ return kerr;
|
+ return kerr;
|
||||||
+}
|
+}
|
||||||
@ -459,7 +526,7 @@ index 07cc87746..cb18861bb 100644
|
|||||||
static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext,
|
static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext,
|
||||||
struct ipadb_mods *imods,
|
struct ipadb_mods *imods,
|
||||||
krb5_db_entry *entry,
|
krb5_db_entry *entry,
|
||||||
@@ -2350,36 +2579,9 @@ static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext,
|
@@ -2350,36 +2624,9 @@ static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext,
|
||||||
|
|
||||||
/* KADM5_ATTRIBUTES */
|
/* KADM5_ATTRIBUTES */
|
||||||
if (entry->mask & KMASK_ATTRIBUTES) {
|
if (entry->mask & KMASK_ATTRIBUTES) {
|
||||||
@ -544,5 +611,5 @@ index 7d2ebae98..d0280940a 100644
|
|||||||
+ * src/lib/krb5/krb/libdef_parse.c:_krb5_conf_boolean() */
|
+ * src/lib/krb5/krb/libdef_parse.c:_krb5_conf_boolean() */
|
||||||
+bool ipa_krb5_parse_bool(const char *str);
|
+bool ipa_krb5_parse_bool(const char *str);
|
||||||
--
|
--
|
||||||
2.44.0
|
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.
|
@ -190,7 +190,7 @@
|
|||||||
|
|
||||||
Name: %{package_name}
|
Name: %{package_name}
|
||||||
Version: %{IPA_VERSION}
|
Version: %{IPA_VERSION}
|
||||||
Release: 10%{?rc_version:.%rc_version}%{?dist}
|
Release: 12%{?rc_version:.%rc_version}%{?dist}
|
||||||
Summary: The Identity, Policy and Audit system
|
Summary: The Identity, Policy and Audit system
|
||||||
|
|
||||||
License: GPLv3+
|
License: GPLv3+
|
||||||
@ -237,6 +237,11 @@ Patch0025: 0025-dcerpc-invalidate-forest-trust-intfo-cache-when-filtering-o
|
|||||||
Patch0026: 0026-backport-test-fixes_rhel#29908.patch
|
Patch0026: 0026-backport-test-fixes_rhel#29908.patch
|
||||||
Patch0027: 0027-kdb-fix-vulnerability-in-GCD-rules-handling.patch
|
Patch0027: 0027-kdb-fix-vulnerability-in-GCD-rules-handling.patch
|
||||||
Patch0028: 0028-kdb-apply-combinatorial-logic-for-ticket-flags.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
|
||||||
%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
|
||||||
@ -1752,6 +1757,22 @@ fi
|
|||||||
%endif
|
%endif
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Wed Jul 17 2024 Rafael Jeffman <rjeffman@redhat.com> - 4.9.13-9
|
||||||
|
- 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
|
* Tue Apr 30 2024 Julien Rische <jrische@redhat.com> - 4.9.13-10
|
||||||
- kdb: apply combinatorial logic for ticket flags (CVE-2024-3183)
|
- kdb: apply combinatorial logic for ticket flags (CVE-2024-3183)
|
||||||
Resolves: RHEL-29927
|
Resolves: RHEL-29927
|
||||||
|
Loading…
Reference in New Issue
Block a user