Set krbCanonicalName=admin@REALM on the admin user

The admin must always own this name. If another entry has this
value set then remove it.

There is a uniqueness plugin for this attribute so the only two
possibilities are:

- no entry has this value set
- the admin user has this value set
- a different entry has the value set

Still, for robustness purposes, the upgrade plugin will handle
more entries.

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
This commit is contained in:
Rob Crittenden authored and Antonio Torres committed 2025-06-17 09:11:34 +02:00
1 parent 6ae52a2fb4
commit e8c410ae5f
4 files changed
+119

No files matched your search

+1
View File
@@ -239,6 +239,7 @@ objectClass: ipasshuser
uid: admin
krbPrincipalName: admin@$REALM
krbPrincipalName: root@$REALM
krbCanonicalName: admin@$REALM
cn: Administrator
sn: Administrator
uidNumber: $IDSTART
@@ -27,6 +27,7 @@ plugin: update_mapping_Guests_to_nobody
plugin: fix_kra_people_entry
plugin: update_pwpolicy
plugin: update_pwpolicy_grace
plugin: add_admin_krbcanonicalname
# last
# DNS version 1
@@ -0,0 +1,79 @@
#
# Copyright (C) 2025 FreeIPA Contributors see COPYING for license
#
from __future__ import absolute_import
import logging
from ipalib import errors
from ipalib import Registry
from ipalib import Updater
from ipapython.dn import DN
logger = logging.getLogger(__name__)
register = Registry()
@register()
class add_admin_krbcanonicalname(Updater):
"""
Ensures that only the admin user has the krbCanonicalName of
admin@$REALM.
"""
def execute(self, **options):
ldap = self.api.Backend.ldap2
search_filter = (
"(krbcanonicalname=admin@{})".format(self.api.env.realm))
try:
(entries, _truncated) = ldap.find_entries(
filter=search_filter, base_dn=self.api.env.basedn,
time_limit=0, size_limit=0)
except errors.EmptyResult:
logger.debug("add_admin_krbcanonicalname: No user set with "
"admin krbcanonicalname")
entries = []
# fall through
except errors.ExecutionError as e:
logger.error("add_admin_krbcanonicalname: Can not get list "
"of krbcanonicalname: %s", e)
return False, []
admin_set = False
# admin should be only user with admin@ as krbcanonicalname
# It has a uniquness setting so there can be only one, we
# just didn't automatically set it for admin.
for entry in entries:
if entry.single_value.get('uid') != 'admin':
logger.critical(
"add_admin_krbcanonicalname: "
"entry %s has a krbcanonicalname of admin. Removing.",
entry.dn)
del entry['krbcanonicalname']
ldap.update_entry(entry)
else:
admin_set = True
if not admin_set:
dn = DN(
('uid', 'admin'),
self.api.env.container_user,
self.api.env.basedn)
entry = ldap.get_entry(dn)
entry['krbcanonicalname'] = 'admin@%s' % self.api.env.realm
try:
ldap.update_entry(entry)
except errors.DuplicateEntry:
logger.critical(
"add_admin_krbcanonicalname: "
"Failed to set krbcanonicalname on admin. It is set "
"on another entry.")
except errors.ExecutionError as e:
logger.critical(
"add_admin_krbcanonicalname: "
"Failed to set krbcanonicalname on admin: %s", e)
return False, []
@@ -1883,6 +1883,44 @@ class TestIPACommandWithoutReplica(IntegrationTest):
assert old_err_msg not in dirsrv_error_log
assert re.search(new_err_msg, dirsrv_error_log)
def test_unique_krbcanonicalname(self):
"""Verify that the uniqueness for krbcanonicalname is working"""
master = self.master
base_dn = str(master.domain.basedn)
hostname = master.hostname
realm = master.domain.realm
principal = f'test/{hostname}@{realm}'
entry_ldif = textwrap.dedent("""
dn: krbprincipalname={principal},cn=services,cn=accounts,{base_dn}
changetype: add
ipakrbprincipalalias: test/{hostname}@{realm}
krbprincipalname: {principal}
objectclass: ipakrbprincipal
objectclass: ipaobject
objectclass: ipaservice
objectclass: krbprincipal
objectclass: krbprincipalaux
objectclass: top
krbcanonicalname: admin@{realm}
managedby: fqdn={hostname},cn=computers,cn=accounts,{base_dn}
""").format(
base_dn=base_dn,
hostname=hostname,
principal=principal,
realm=realm)
tasks.kdestroy_all(master)
master.run_command(
['kinit', '-kt', '/etc/krb5.keytab', f'host/{hostname}@{realm}'])
args = [
'ldapmodify',
'-Y',
'GSSAPI'
]
result = master.run_command(args, stdin_text=entry_ldif,
raiseonerr=False)
assert "entry with the same attribute value" in result.stderr_text
class TestIPAautomount(IntegrationTest):
@classmethod