From 0c2d0bb2b0f6b56f57b592ffc8784a0dfa1c9a48 Mon Sep 17 00:00:00 2001 From: Martin Kosek Date: Oct 02 2012 19:17:42 +0000 Subject: Fill ipakrbprincipalalias on upgrades From IPA 3.0, services have by default ipakrbprincipal objectclass which allows ipakrbprincipalalias attribute used for case-insensitive principal searches. However, services created in previous version do not have this objectclass (and attribute) and thus case-insensitive searches may return inconsistent results. Fill ipakrbprincipalalias on upgrades for all 2.x services. Also treat Treat the ipakrbprincipal as optional to avoid missing services in service-find command if the upgrade fails for any reason. https://fedorahosted.org/freeipa/ticket/3106 --- diff --git a/ipalib/plugins/service.py b/ipalib/plugins/service.py index 120eb60..a3d436e 100644 --- a/ipalib/plugins/service.py +++ b/ipalib/plugins/service.py @@ -221,8 +221,9 @@ class service(LDAPObject): object_name_plural = _('services') object_class = [ 'krbprincipal', 'krbprincipalaux', 'krbticketpolicyaux', 'ipaobject', - 'ipaservice', 'pkiuser', 'ipakrbprincipal' + 'ipaservice', 'pkiuser' ] + possible_objectclasses = ['ipakrbprincipal'] search_attributes = ['krbprincipalname', 'managedby', 'ipakrbauthzdata'] default_attributes = ['krbprincipalname', 'usercertificate', 'managedby', 'ipakrbauthzdata',] @@ -327,6 +328,10 @@ class service_add(LDAPCreate): # schema entry_attrs['ipakrbprincipalalias'] = keys[-1] + # Objectclass ipakrbprincipal providing ipakrbprincipalalias is not in + # in a list of default objectclasses, add it manually + entry_attrs['objectclass'].append('ipakrbprincipal') + return dn api.register(service_add) diff --git a/ipaserver/install/plugins/Makefile.am b/ipaserver/install/plugins/Makefile.am index 9670273..d29103a 100644 --- a/ipaserver/install/plugins/Makefile.am +++ b/ipaserver/install/plugins/Makefile.am @@ -8,6 +8,7 @@ app_PYTHON = \ rename_managed.py \ dns.py \ updateclient.py \ + update_services.py \ $(NULL) EXTRA_DIST = \ diff --git a/ipaserver/install/plugins/update_services.py b/ipaserver/install/plugins/update_services.py new file mode 100644 index 0000000..c384af5 --- /dev/null +++ b/ipaserver/install/plugins/update_services.py @@ -0,0 +1,95 @@ +# Authors: +# Martin Kosek +# +# Copyright (C) 2012 Red Hat +# see file 'COPYING' for use and warranty information +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from ipaserver.install.plugins import MIDDLE +from ipaserver.install.plugins.baseupdate import PostUpdate +from ipalib import api, errors +from ipapython.dn import DN +from ipapython.ipa_log_manager import * + + +class update_service_principalalias(PostUpdate): + """ + Update all services which do not have ipakrbprincipalalias attribute + used for case-insensitive principal searches filled. This applies for + all services created prior IPA 3.0. + """ + order = MIDDLE + + def execute(self, **options): + ldap = self.obj.backend + + base_dn = DN(api.env.container_service, api.env.basedn) + search_filter = ("(&(objectclass=krbprincipal)(objectclass=ipaservice)" + "(!(objectclass=ipakrbprincipal)))") + root_logger.debug("update_service_principalalias: search for affected " + "services") + + while True: + # run the search in loop to avoid issues when LDAP limits are hit + # during update + try: + (entries, truncated) = ldap.find_entries(search_filter, + ['objectclass', 'krbprincipalname'], base_dn, + time_limit=0, size_limit=0) + except errors.NotFound: + root_logger.debug("update_service_principalalias: no service " + "to update found") + return (False, False, []) + except errors.ExecutionError, e: + root_logger.error("update_service_principalalias: cannot " + "retrieve list of affected services: %s", e) + return (False, False, []) + if not entries: + # no entry was returned, rather break than continue cycling + root_logger.debug("update_service_principalalias: no service " + "was returned") + return (False, False, []) + root_logger.debug("update_service_principalalias: found %d " + "services to update, truncated: %s", + len(entries), truncated) + + error = False + for dn, entry in entries: + update = {} + update['objectclass'] = (entry['objectclass'] + + ['ipakrbprincipal']) + update['ipakrbprincipalalias'] = entry['krbprincipalname'] + try: + ldap.update_entry(dn, update) + except (errors.EmptyModlist, errors.NotFound): + pass + except errors.ExecutionError, e: + root_logger.debug("update_service_principalalias: cannot " + "update service: %s", e) + error = True + + if error: + # exit loop to avoid infinite cycles + root_logger.error("update_service_principalalias: error(s)" + "detected during service update") + return (False, False, []) + elif not truncated: + # all affected entries updated, exit the loop + root_logger.debug("update_service_principalalias: all affected" + " services updated") + return (False, False, []) + return (False, False, []) + +api.register(update_service_principalalias)