summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorence Blanc-Renaud <flo@redhat.com>2017-08-28 10:50:58 +0200
committerStanislav Laznicka <slaznick@redhat.com>2017-08-30 12:47:53 +0200
commit69bda6b440d6b84f042ff74b9ce708d963616eda (patch)
tree64273f98ec9faa81fde59a42ed17bb78d5bc477b
parent1b78f79283e633abc5dd901ca4db99cea36aca1a (diff)
downloadfreeipa-69bda6b440d6b84f042ff74b9ce708d963616eda.tar.gz
freeipa-69bda6b440d6b84f042ff74b9ce708d963616eda.tar.xz
freeipa-69bda6b440d6b84f042ff74b9ce708d963616eda.zip
Fix ipa-server-upgrade: This entry already exists
ipa-server-upgrade fails when running the ipaload_cacrt plugin. The plugin finds all CA certificates in /etc/httpd/alias and uploads them in LDAP below cn=certificates,cn=ipa,cn=etc,$BASEDN. The issue happens because there is already an entry in LDAP for IPA CA, but with a different DN. The nickname in /etc/httpd/alias can differ from $DOMAIN IPA CA. To avoid the issue: 1/ during upgrade, run a new plugin that removes duplicates and restarts ldap (to make sure that uniqueness attr plugin is working after the new plugin) 2/ modify upload_cacert plugin so that it is using $DOMAIN IPA CA instead of cn=$nickname,cn=ipa,cn=etc,$BASEDN when uploading IPA CA. https://pagure.io/freeipa/issue/7125 Reviewed-By: Fraser Tweedale <ftweedal@redhat.com>
-rw-r--r--install/updates/90-post_upgrade_plugins.update1
-rw-r--r--ipalib/install/certstore.py19
-rw-r--r--ipaserver/install/plugins/update_fix_duplicate_cacrt_in_ldap.py84
-rw-r--r--ipaserver/install/plugins/upload_cacrt.py16
4 files changed, 118 insertions, 2 deletions
diff --git a/install/updates/90-post_upgrade_plugins.update b/install/updates/90-post_upgrade_plugins.update
index 8477199e0..bbc3e2942 100644
--- a/install/updates/90-post_upgrade_plugins.update
+++ b/install/updates/90-post_upgrade_plugins.update
@@ -15,6 +15,7 @@ plugin: update_ca_renewal_master
plugin: update_idrange_type
plugin: update_pacs
plugin: update_service_principalalias
+plugin: update_fix_duplicate_cacrt_in_ldap
plugin: update_upload_cacrt
# update_ra_cert_store has to be executed after update_ca_renewal_master
plugin: update_ra_cert_store
diff --git a/ipalib/install/certstore.py b/ipalib/install/certstore.py
index 481918b99..8b182958c 100644
--- a/ipalib/install/certstore.py
+++ b/ipalib/install/certstore.py
@@ -27,6 +27,7 @@ from pyasn1.error import PyAsn1Error
from ipapython.dn import DN
from ipapython.certdb import get_ca_nickname, TrustFlags
from ipalib import errors, x509
+from ipalib.constants import IPA_CA_CN
def _parse_cert(cert):
@@ -385,3 +386,21 @@ def get_ca_certs_nss(ldap, base_dn, compat_realm, compat_ipa_ca,
nss_certs.append((cert, nickname, trust_flags))
return nss_certs
+
+
+def get_ca_subject(ldap, container_ca, base_dn):
+ """
+ Look for the IPA CA certificate subject.
+ """
+ dn = DN(('cn', IPA_CA_CN), container_ca, base_dn)
+ try:
+ cacert_subject = ldap.get_entry(dn)['ipacasubjectdn'][0]
+ except errors.NotFound:
+ # if the entry doesn't exist, we are dealing with a pre-v4.4
+ # installation, where the default CA subject was always based
+ # on the subject_base.
+ attrs = ldap.get_ipa_config()
+ subject_base = attrs.get('ipacertificatesubjectbase')[0]
+ cacert_subject = DN(('CN', 'Certificate Authority'), subject_base)
+
+ return cacert_subject
diff --git a/ipaserver/install/plugins/update_fix_duplicate_cacrt_in_ldap.py b/ipaserver/install/plugins/update_fix_duplicate_cacrt_in_ldap.py
new file mode 100644
index 000000000..cd4f13a8e
--- /dev/null
+++ b/ipaserver/install/plugins/update_fix_duplicate_cacrt_in_ldap.py
@@ -0,0 +1,84 @@
+# Authors:
+# Florence Blanc-Renaud <flo@redhat.com>
+#
+# Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
+
+import logging
+
+from ipalib import Registry, errors
+from ipalib import Updater
+from ipalib.install import certstore
+from ipapython.dn import DN
+from ipapython.certdb import get_ca_nickname
+
+logger = logging.getLogger(__name__)
+
+register = Registry()
+
+
+@register()
+class update_fix_duplicate_cacrt_in_ldap(Updater):
+ """
+ When multiple entries exist for IPA CA cert in ldap, remove the duplicate
+
+ After this plugin, ds needs to be restarted. This ensures that
+ the attribute uniqueness plugin is working and prevents
+ other plugins from adding duplicates.
+ """
+
+ def execute(self, **options):
+ # If CA is disabled, no need to check for duplicates of IPA CA
+ ca_enabled = self.api.Command.ca_is_enabled()['result']
+ if not ca_enabled:
+ return True, []
+
+ # Look for the IPA CA cert subject
+ ldap = self.api.Backend.ldap2
+ cacert_subject = certstore.get_ca_subject(
+ ldap,
+ self.api.env.container_ca,
+ self.api.env.basedn)
+
+ # Find if there are other certificates with the same subject
+ # They are duplicates resulting of BZ 1480102
+ base_dn = DN(('cn', 'certificates'), ('cn', 'ipa'), ('cn', 'etc'),
+ self.api.env.basedn)
+ try:
+ filter = ldap.make_filter({'ipaCertSubject': cacert_subject})
+ result, _truncated = ldap.find_entries(
+ base_dn=base_dn,
+ filter=filter,
+ attrs_list=[])
+ except errors.NotFound:
+ # No duplicate, we're good
+ logger.debug("No duplicates for IPA CA in LDAP")
+ return True, []
+
+ logger.debug("Found %d entrie(s) for IPA CA in LDAP", len(result))
+ cacert_dn = DN(('cn', get_ca_nickname(self.api.env.realm)), base_dn)
+ for entry in result:
+ if entry.dn == cacert_dn:
+ continue
+ # Remove the duplicate
+ try:
+ ldap.delete_entry(entry)
+ logger.debug("Removed the duplicate %s", entry.dn)
+ except Exception as e:
+ logger.warning("Failed to remove the duplicate %s: %s",
+ entry.dn, e)
+
+ return True, []
diff --git a/ipaserver/install/plugins/upload_cacrt.py b/ipaserver/install/plugins/upload_cacrt.py
index a71ba602c..11b5cf6eb 100644
--- a/ipaserver/install/plugins/upload_cacrt.py
+++ b/ipaserver/install/plugins/upload_cacrt.py
@@ -45,6 +45,10 @@ class update_upload_cacrt(Updater):
ca_enabled = self.api.Command.ca_is_enabled()['result']
if ca_enabled:
ca_nickname = certdb.get_ca_nickname(self.api.env.realm)
+ ca_subject = certstore.get_ca_subject(
+ self.api.Backend.ldap2,
+ self.api.env.container_ca,
+ self.api.env.basedn)
else:
ca_nickname = None
server_certs = db.find_server_certs()
@@ -58,9 +62,17 @@ class update_upload_cacrt(Updater):
for nickname, trust_flags in db.list_certs():
if trust_flags.has_key:
continue
- if nickname == ca_nickname and ca_enabled:
- trust_flags = certdb.IPA_CA_TRUST_FLAGS
cert = db.get_cert_from_db(nickname)
+ subject = cert.subject
+ if ca_enabled and subject == ca_subject:
+ # When ca is enabled, we can have the IPA CA cert stored
+ # in the nss db with a different nickname (for instance
+ # when the server was installed with --subject to
+ # customize the CA cert subject), but it must always be
+ # stored in LDAP with the DN cn=$DOMAIN IPA CA
+ # This is why we check the subject instead of the nickname here
+ nickname = ca_nickname
+ trust_flags = certdb.IPA_CA_TRUST_FLAGS
trust, _ca, eku = certstore.trust_flags_to_key_policy(trust_flags)
dn = DN(('cn', nickname), ('cn', 'certificates'), ('cn', 'ipa'),