diff --git a/install/updates/90-post_upgrade_plugins.update b/install/updates/90-post_upgrade_plugins.update index 8eb197739..26b8820e8 100644 --- a/install/updates/90-post_upgrade_plugins.update +++ b/install/updates/90-post_upgrade_plugins.update @@ -23,6 +23,7 @@ plugin: update_upload_cacrt # update_ra_cert_store has to be executed after update_ca_renewal_master plugin: update_ra_cert_store plugin: update_mapping_Guests_to_nobody +plugin: fix_kra_people_entry # last # DNS version 1 diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py index 46c9c63ea..c23f73ac5 100644 --- a/ipaserver/install/krainstance.py +++ b/ipaserver/install/krainstance.py @@ -50,6 +50,9 @@ ADMIN_GROUPS = [ 'Security Domain Administrators' ] +KRA_BASEDN = DN(('o', 'kra'), ('o', 'ipaca')) +KRA_AGENT_DN = DN(('uid', 'ipakra'), ('ou', 'people'), KRA_BASEDN) + class KRAInstance(DogtagInstance): """ @@ -77,8 +80,6 @@ class KRAInstance(DogtagInstance): config=paths.KRA_CS_CFG_PATH, ) - self.basedn = DN(('o', 'kra'), ('o', 'ipaca')) - def configure_instance(self, realm_name, host_name, dm_password, admin_password, pkcs12_info=None, master_host=None, subject_base=None, ca_subject=None, @@ -247,9 +248,8 @@ class KRAInstance(DogtagInstance): conn.connect(autobind=True) # create ipakra user with RA agent certificate - user_dn = DN(('uid', "ipakra"), ('ou', 'people'), self.basedn) entry = conn.make_entry( - user_dn, + KRA_AGENT_DN, objectClass=['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'cmsuser'], uid=["ipakra"], @@ -264,9 +264,10 @@ class KRAInstance(DogtagInstance): conn.add_entry(entry) # add ipakra user to Data Recovery Manager Agents group - group_dn = DN(('cn', 'Data Recovery Manager Agents'), ('ou', 'groups'), - self.basedn) - conn.add_entry_to_group(user_dn, group_dn, 'uniqueMember') + group_dn = DN( + ('cn', 'Data Recovery Manager Agents'), ('ou', 'groups'), + KRA_BASEDN) + conn.add_entry_to_group(KRA_AGENT_DN, group_dn, 'uniqueMember') conn.disconnect() diff --git a/ipaserver/install/plugins/fix_kra_people_entry.py b/ipaserver/install/plugins/fix_kra_people_entry.py new file mode 100644 index 000000000..6f9d9ed47 --- /dev/null +++ b/ipaserver/install/plugins/fix_kra_people_entry.py @@ -0,0 +1,76 @@ +# +# Copyright (C) 2019 FreeIPA Contributors see COPYING for license +# + +import logging + +from ipalib import Registry, Updater, x509 +from ipapython.dn import DN +from ipaplatform.paths import paths +from ipaserver.install import krainstance + +logger = logging.getLogger(__name__) + +register = Registry() + + +@register() +class fix_kra_people_entry(Updater): + """ + Update the KRA uid=ipakra agent user entry. + + There was a bug where this was created with an incorrect + 'description' attribute, breaking authentication: + https://pagure.io/freeipa/issue/8084. + + """ + def execute(self, **options): + kra = krainstance.KRAInstance(self.api.env.realm) + if not kra.is_installed(): + return False, [] + + cert = x509.load_certificate_from_file(paths.RA_AGENT_PEM) + entry = self.api.Backend.ldap2.get_entry(krainstance.KRA_AGENT_DN) + + # check description attribute + description_values = entry.get('description', []) + if len(description_values) < 1: + # missing 'description' attribute is unexpected, but we can + # add it + do_fix = True + else: + # There should only be one value, so we will take the first value. + # But ignore the serial number when comparing, just in case. + description = description_values[0] + parts = description.split(';', 2) # see below for syntax + + if len(parts) < 3: + do_fix = True # syntax error (not expected) + elif parts[2] != '{};{}'.format(DN(cert.issuer), DN(cert.subject)): + # issuer/subject does not match cert. THIS is the condition + # caused by issue 8084, which we want to fix. + do_fix = True + else: + do_fix = False # everything is fine + + if do_fix: + # If other replicas have a different iteration of the IPA RA + # cert (e.g. renewal was triggered prematurely on some master + # and not on others) then authentication on those replicas will + # fail. But the 'description' attribute needed fixing because + # the issuer value was wrong, meaning authentication was broken + # on ALL replicas. So even for the corner case where different + # replicas have different IPA RA certs, updating the attribute + # will at least mean THIS replica can authenticate to the KRA. + + logger.debug("Fixing KRA user entry 'description' attribute") + entry['description'] = [ + '2;{};{};{}'.format( + cert.serial_number, + DN(cert.issuer), + DN(cert.subject) + ) + ] + self.api.Backend.ldap2.update_entry(entry) + + return False, [] # don't restart DS; no LDAP updates to perform