|
|
460745 |
From c9fb09190ac243bcf45622693944d7e6785141b4 Mon Sep 17 00:00:00 2001
|
|
|
460745 |
From: Florence Blanc-Renaud <flo@redhat.com>
|
|
|
460745 |
Date: Mon, 28 Aug 2017 10:50:58 +0200
|
|
|
460745 |
Subject: [PATCH] Backport PR 1008 to ipa-4-5 Fix ipa-server-upgrade: This
|
|
|
460745 |
entry already exists
|
|
|
460745 |
|
|
|
460745 |
ipa-server-upgrade fails when running the ipaload_cacrt plugin. The plugin
|
|
|
460745 |
finds all CA certificates in /etc/httpd/alias and uploads them in LDAP
|
|
|
460745 |
below cn=certificates,cn=ipa,cn=etc,$BASEDN.
|
|
|
460745 |
The issue happens because there is already an entry in LDAP for IPA CA, but
|
|
|
460745 |
with a different DN. The nickname in /etc/httpd/alias can differ from
|
|
|
460745 |
$DOMAIN IPA CA.
|
|
|
460745 |
|
|
|
460745 |
To avoid the issue:
|
|
|
460745 |
1/ during upgrade, run a new plugin that removes duplicates and restarts ldap
|
|
|
460745 |
(to make sure that uniqueness attr plugin is working after the new plugin)
|
|
|
460745 |
2/ modify upload_cacert plugin so that it is using $DOMAIN IPA CA instead of
|
|
|
460745 |
cn=$nickname,cn=ipa,cn=etc,$BASEDN when uploading IPA CA.
|
|
|
460745 |
|
|
|
460745 |
https://pagure.io/freeipa/issue/7125
|
|
|
460745 |
|
|
|
460745 |
Reviewed-By: Fraser Tweedale <ftweedal@redhat.com>
|
|
|
460745 |
---
|
|
|
460745 |
install/updates/90-post_upgrade_plugins.update | 1 +
|
|
|
460745 |
ipalib/install/certstore.py | 19 +++++
|
|
|
460745 |
.../plugins/update_fix_duplicate_cacrt_in_ldap.py | 84 ++++++++++++++++++++++
|
|
|
460745 |
ipaserver/install/plugins/upload_cacrt.py | 19 ++++-
|
|
|
460745 |
4 files changed, 120 insertions(+), 3 deletions(-)
|
|
|
460745 |
create mode 100644 ipaserver/install/plugins/update_fix_duplicate_cacrt_in_ldap.py
|
|
|
460745 |
|
|
|
460745 |
diff --git a/install/updates/90-post_upgrade_plugins.update b/install/updates/90-post_upgrade_plugins.update
|
|
|
460745 |
index 8477199e07d6729d5847e58bfa67d061bd1410c2..bbc3e29422fc0f139c2ca68a7033863e4c25f8cf 100644
|
|
|
460745 |
--- a/install/updates/90-post_upgrade_plugins.update
|
|
|
460745 |
+++ b/install/updates/90-post_upgrade_plugins.update
|
|
|
460745 |
@@ -15,6 +15,7 @@ plugin: update_ca_renewal_master
|
|
|
460745 |
plugin: update_idrange_type
|
|
|
460745 |
plugin: update_pacs
|
|
|
460745 |
plugin: update_service_principalalias
|
|
|
460745 |
+plugin: update_fix_duplicate_cacrt_in_ldap
|
|
|
460745 |
plugin: update_upload_cacrt
|
|
|
460745 |
# update_ra_cert_store has to be executed after update_ca_renewal_master
|
|
|
460745 |
plugin: update_ra_cert_store
|
|
|
460745 |
diff --git a/ipalib/install/certstore.py b/ipalib/install/certstore.py
|
|
|
460745 |
index bc2079fb12873444cbe6796eebfdfcfebd0e284d..76181fe47de585974f3fb33ec586f5c576adebb5 100644
|
|
|
460745 |
--- a/ipalib/install/certstore.py
|
|
|
460745 |
+++ b/ipalib/install/certstore.py
|
|
|
460745 |
@@ -27,6 +27,7 @@ from pyasn1.error import PyAsn1Error
|
|
|
460745 |
from ipapython.dn import DN
|
|
|
460745 |
from ipapython.certdb import get_ca_nickname, TrustFlags
|
|
|
460745 |
from ipalib import errors, x509
|
|
|
460745 |
+from ipalib.constants import IPA_CA_CN
|
|
|
460745 |
|
|
|
460745 |
def _parse_cert(dercert):
|
|
|
460745 |
try:
|
|
|
460745 |
@@ -381,3 +382,21 @@ def get_ca_certs_nss(ldap, base_dn, compat_realm, compat_ipa_ca,
|
|
|
460745 |
nss_certs.append((cert, nickname, trust_flags))
|
|
|
460745 |
|
|
|
460745 |
return nss_certs
|
|
|
460745 |
+
|
|
|
460745 |
+
|
|
|
460745 |
+def get_ca_subject(ldap, container_ca, base_dn):
|
|
|
460745 |
+ """
|
|
|
460745 |
+ Look for the IPA CA certificate subject.
|
|
|
460745 |
+ """
|
|
|
460745 |
+ dn = DN(('cn', IPA_CA_CN), container_ca, base_dn)
|
|
|
460745 |
+ try:
|
|
|
460745 |
+ cacert_subject = ldap.get_entry(dn)['ipacasubjectdn'][0]
|
|
|
460745 |
+ except errors.NotFound:
|
|
|
460745 |
+ # if the entry doesn't exist, we are dealing with a pre-v4.4
|
|
|
460745 |
+ # installation, where the default CA subject was always based
|
|
|
460745 |
+ # on the subject_base.
|
|
|
460745 |
+ attrs = ldap.get_ipa_config()
|
|
|
460745 |
+ subject_base = attrs.get('ipacertificatesubjectbase')[0]
|
|
|
460745 |
+ cacert_subject = DN(('CN', 'Certificate Authority'), subject_base)
|
|
|
460745 |
+
|
|
|
460745 |
+ return cacert_subject
|
|
|
460745 |
diff --git a/ipaserver/install/plugins/update_fix_duplicate_cacrt_in_ldap.py b/ipaserver/install/plugins/update_fix_duplicate_cacrt_in_ldap.py
|
|
|
460745 |
new file mode 100644
|
|
|
460745 |
index 0000000000000000000000000000000000000000..cd4f13a8eb6b5bc9e04fcdd407907497528f8be1
|
|
|
460745 |
--- /dev/null
|
|
|
460745 |
+++ b/ipaserver/install/plugins/update_fix_duplicate_cacrt_in_ldap.py
|
|
|
460745 |
@@ -0,0 +1,84 @@
|
|
|
460745 |
+# Authors:
|
|
|
460745 |
+# Florence Blanc-Renaud <flo@redhat.com>
|
|
|
460745 |
+#
|
|
|
460745 |
+# Copyright (C) 2017 Red Hat
|
|
|
460745 |
+# see file 'COPYING' for use and warranty information
|
|
|
460745 |
+#
|
|
|
460745 |
+# This program is free software; you can redistribute it and/or modify
|
|
|
460745 |
+# it under the terms of the GNU General Public License as published by
|
|
|
460745 |
+# the Free Software Foundation, either version 3 of the License, or
|
|
|
460745 |
+# (at your option) any later version.
|
|
|
460745 |
+#
|
|
|
460745 |
+# This program is distributed in the hope that it will be useful,
|
|
|
460745 |
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
460745 |
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
460745 |
+# GNU General Public License for more details.
|
|
|
460745 |
+#
|
|
|
460745 |
+# You should have received a copy of the GNU General Public License
|
|
|
460745 |
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
460745 |
+
|
|
|
460745 |
+import logging
|
|
|
460745 |
+
|
|
|
460745 |
+from ipalib import Registry, errors
|
|
|
460745 |
+from ipalib import Updater
|
|
|
460745 |
+from ipalib.install import certstore
|
|
|
460745 |
+from ipapython.dn import DN
|
|
|
460745 |
+from ipapython.certdb import get_ca_nickname
|
|
|
460745 |
+
|
|
|
460745 |
+logger = logging.getLogger(__name__)
|
|
|
460745 |
+
|
|
|
460745 |
+register = Registry()
|
|
|
460745 |
+
|
|
|
460745 |
+
|
|
|
460745 |
+@register()
|
|
|
460745 |
+class update_fix_duplicate_cacrt_in_ldap(Updater):
|
|
|
460745 |
+ """
|
|
|
460745 |
+ When multiple entries exist for IPA CA cert in ldap, remove the duplicate
|
|
|
460745 |
+
|
|
|
460745 |
+ After this plugin, ds needs to be restarted. This ensures that
|
|
|
460745 |
+ the attribute uniqueness plugin is working and prevents
|
|
|
460745 |
+ other plugins from adding duplicates.
|
|
|
460745 |
+ """
|
|
|
460745 |
+
|
|
|
460745 |
+ def execute(self, **options):
|
|
|
460745 |
+ # If CA is disabled, no need to check for duplicates of IPA CA
|
|
|
460745 |
+ ca_enabled = self.api.Command.ca_is_enabled()['result']
|
|
|
460745 |
+ if not ca_enabled:
|
|
|
460745 |
+ return True, []
|
|
|
460745 |
+
|
|
|
460745 |
+ # Look for the IPA CA cert subject
|
|
|
460745 |
+ ldap = self.api.Backend.ldap2
|
|
|
460745 |
+ cacert_subject = certstore.get_ca_subject(
|
|
|
460745 |
+ ldap,
|
|
|
460745 |
+ self.api.env.container_ca,
|
|
|
460745 |
+ self.api.env.basedn)
|
|
|
460745 |
+
|
|
|
460745 |
+ # Find if there are other certificates with the same subject
|
|
|
460745 |
+ # They are duplicates resulting of BZ 1480102
|
|
|
460745 |
+ base_dn = DN(('cn', 'certificates'), ('cn', 'ipa'), ('cn', 'etc'),
|
|
|
460745 |
+ self.api.env.basedn)
|
|
|
460745 |
+ try:
|
|
|
460745 |
+ filter = ldap.make_filter({'ipaCertSubject': cacert_subject})
|
|
|
460745 |
+ result, _truncated = ldap.find_entries(
|
|
|
460745 |
+ base_dn=base_dn,
|
|
|
460745 |
+ filter=filter,
|
|
|
460745 |
+ attrs_list=[])
|
|
|
460745 |
+ except errors.NotFound:
|
|
|
460745 |
+ # No duplicate, we're good
|
|
|
460745 |
+ logger.debug("No duplicates for IPA CA in LDAP")
|
|
|
460745 |
+ return True, []
|
|
|
460745 |
+
|
|
|
460745 |
+ logger.debug("Found %d entrie(s) for IPA CA in LDAP", len(result))
|
|
|
460745 |
+ cacert_dn = DN(('cn', get_ca_nickname(self.api.env.realm)), base_dn)
|
|
|
460745 |
+ for entry in result:
|
|
|
460745 |
+ if entry.dn == cacert_dn:
|
|
|
460745 |
+ continue
|
|
|
460745 |
+ # Remove the duplicate
|
|
|
460745 |
+ try:
|
|
|
460745 |
+ ldap.delete_entry(entry)
|
|
|
460745 |
+ logger.debug("Removed the duplicate %s", entry.dn)
|
|
|
460745 |
+ except Exception as e:
|
|
|
460745 |
+ logger.warning("Failed to remove the duplicate %s: %s",
|
|
|
460745 |
+ entry.dn, e)
|
|
|
460745 |
+
|
|
|
460745 |
+ return True, []
|
|
|
460745 |
diff --git a/ipaserver/install/plugins/upload_cacrt.py b/ipaserver/install/plugins/upload_cacrt.py
|
|
|
460745 |
index a1957ca5b675b86f0df36dc820ee31305f54f863..985b74c06e80a3620eb6454c0bd9c7590b04184d 100644
|
|
|
460745 |
--- a/ipaserver/install/plugins/upload_cacrt.py
|
|
|
460745 |
+++ b/ipaserver/install/plugins/upload_cacrt.py
|
|
|
460745 |
@@ -20,7 +20,7 @@
|
|
|
460745 |
from ipalib.install import certstore
|
|
|
460745 |
from ipaplatform.paths import paths
|
|
|
460745 |
from ipaserver.install import certs
|
|
|
460745 |
-from ipalib import Registry, errors
|
|
|
460745 |
+from ipalib import Registry, errors, x509
|
|
|
460745 |
from ipalib import Updater
|
|
|
460745 |
from ipapython import certdb
|
|
|
460745 |
from ipapython.dn import DN
|
|
|
460745 |
@@ -41,6 +41,10 @@ class update_upload_cacrt(Updater):
|
|
|
460745 |
ca_enabled = self.api.Command.ca_is_enabled()['result']
|
|
|
460745 |
if ca_enabled:
|
|
|
460745 |
ca_nickname = certdb.get_ca_nickname(self.api.env.realm)
|
|
|
460745 |
+ ca_subject = certstore.get_ca_subject(
|
|
|
460745 |
+ self.api.Backend.ldap2,
|
|
|
460745 |
+ self.api.env.container_ca,
|
|
|
460745 |
+ self.api.env.basedn)
|
|
|
460745 |
else:
|
|
|
460745 |
ca_nickname = None
|
|
|
460745 |
server_certs = db.find_server_certs()
|
|
|
460745 |
@@ -54,9 +58,18 @@ class update_upload_cacrt(Updater):
|
|
|
460745 |
for nickname, trust_flags in db.list_certs():
|
|
|
460745 |
if trust_flags.has_key:
|
|
|
460745 |
continue
|
|
|
460745 |
- if nickname == ca_nickname and ca_enabled:
|
|
|
460745 |
- trust_flags = certdb.IPA_CA_TRUST_FLAGS
|
|
|
460745 |
cert = db.get_cert_from_db(nickname, pem=False)
|
|
|
460745 |
+ subject = DN(
|
|
|
460745 |
+ x509.load_certificate(cert, datatype=x509.DER).subject)
|
|
|
460745 |
+ if ca_enabled and subject == ca_subject:
|
|
|
460745 |
+ # When ca is enabled, we can have the IPA CA cert stored
|
|
|
460745 |
+ # in the nss db with a different nickname (for instance
|
|
|
460745 |
+ # when the server was installed with --subject to
|
|
|
460745 |
+ # customize the CA cert subject), but it must always be
|
|
|
460745 |
+ # stored in LDAP with the DN cn=$DOMAIN IPA CA
|
|
|
460745 |
+ # This is why we check the subject instead of the nickname here
|
|
|
460745 |
+ nickname = ca_nickname
|
|
|
460745 |
+ trust_flags = certdb.IPA_CA_TRUST_FLAGS
|
|
|
460745 |
trust, _ca, eku = certstore.trust_flags_to_key_policy(trust_flags)
|
|
|
460745 |
|
|
|
460745 |
dn = DN(('cn', nickname), ('cn', 'certificates'), ('cn', 'ipa'),
|
|
|
460745 |
--
|
|
|
460745 |
2.13.5
|