[Freeipa-devel] [PATCH] 0020..0022 pki-related upgrade fixes

Fraser Tweedale ftweedal at redhat.com
Fri Jun 19 07:28:38 UTC 2015


The attached patches fix upgrade issues when pki is also updated
from pre 10.2.4.

pki dependency is bumped to 10.2.5 - the official builds should be
done Friday (US time) but it is available from my copr[1].  If
someone wants to add to official freeipa COPR in meantime the SRPM
is here[2].

[1] https://copr.fedoraproject.org/coprs/ftweedal/freeipa/
[2] https://ftweedal.fedorapeople.org/pki-core-10.2.5-0.2.fc21.src.rpm

Thanks,
Fraser
-------------- next part --------------
From 00848315ad19a9acdc132904c143c8951e028e67 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Fri, 19 Jun 2015 01:37:26 -0400
Subject: [PATCH 20/22] Upgrade: disconnect ldap2 after adding CA DNS records

Non-disconnection of ldap2 backend in 'add_ca_dns_records' seems to
be causing problems with later uses.  Avoid the problem by
disconnecting it before returning.
---
 ipaserver/install/server/upgrade.py | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index a9dac59e009f5646630b7a8dd0e92f39b5a44a86..a949af58ff3f0b1df03e23fed6575e669f97cb15 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -1038,6 +1038,7 @@ def add_ca_dns_records():
     if not ret['result']:
         root_logger.info('DNS is not configured')
         sysupgrade.set_upgrade_state('dns', 'ipa_ca_records', True)
+        api.Backend.ldap2.disconnect()
         return
 
     bind = bindinstance.BindInstance()
@@ -1050,6 +1051,7 @@ def add_ca_dns_records():
                                 ca_configured=None)
 
     sysupgrade.set_upgrade_state('dns', 'ipa_ca_records', True)
+    api.Backend.ldap2.disconnect()
 
 
 def find_subject_base():
-- 
2.1.0

-------------- next part --------------
From 56c95d5258ffff2c4364910994a05017498df204 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <frase at frase.id.au>
Date: Tue, 16 Jun 2015 07:40:36 -0400
Subject: [PATCH 21/22] Upgrade CA schema during upgrade

New schema (for LDAP-based profiles) was introduced in Dogtag, but
Dogtag does not yet have a reliable method for upgrading its schema.
Use FreeIPA's schema update machinery to add the new attributeTypes
and objectClasses defined by Dogtag.

Also update the pki dependencies to 10.2.5, which provides the
schema update file.
---
 freeipa.spec.in                     |  6 +++---
 ipaserver/install/server/upgrade.py | 26 ++++++++++++++++++++++++++
 2 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/freeipa.spec.in b/freeipa.spec.in
index 809ac1e5bb877c85e29c082ecfb9ad91aa97b4f5..a8c70f8a414855bb00bf4048ad788e455d0b94e2 100644
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -92,7 +92,7 @@ BuildRequires:  python-backports-ssl_match_hostname
 BuildRequires:  softhsm-devel >= 2.0.0rc1-1
 BuildRequires:  openssl-devel
 BuildRequires:  p11-kit-devel
-BuildRequires:  pki-base >= 10.2.4-1
+BuildRequires:  pki-base >= 10.2.5
 BuildRequires:  python-pytest-multihost >= 0.5
 BuildRequires:  python-pytest-sourceorder
 
@@ -135,8 +135,8 @@ Requires(post): systemd-units
 Requires: selinux-policy >= %{selinux_policy_version}
 Requires(post): selinux-policy-base
 Requires: slapi-nis >= 0.54.2-1
-Requires: pki-ca >= 10.2.4-1
-Requires: pki-kra >= 10.2.4-1
+Requires: pki-ca >= 10.2.5
+Requires: pki-kra >= 10.2.5
 Requires(preun): python systemd-units
 Requires(postun): python systemd-units
 Requires: python-dns >= 1.11.1
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index a949af58ff3f0b1df03e23fed6575e669f97cb15..78a4ace82f35193652cc535423309c67bca09df4 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -1256,6 +1256,31 @@ def update_mod_nss_protocol(http):
     sysupgrade.set_upgrade_state('nss.conf', 'protocol_updated_tls12', True)
 
 
+def ca_upgrade_schema(ca):
+    root_logger.info('[Upgrading CA schema]')
+    if not ca.is_configured():
+        root_logger.info('CA is not configured')
+        return False
+
+    realm = krbV.default_context().default_realm
+    upgrade = IPAUpgrade(realm,
+        schema_files=['/usr/share/pki/server/conf/schema-certProfile.ldif'])
+    try:
+        upgrade.create_instance()
+    except BadSyntax:
+        raise RuntimeError(
+            'Bad syntax detected in CA schema file(s).', 1)
+    except RuntimeError:
+        raise RuntimeError('CA schema upgrade failed.', 1)
+    else:
+        if upgrade.modified:
+            root_logger.info('CA schema update complete')
+            return True
+        else:
+            root_logger.info('CA schema update complete (no changes)')
+            return False
+
+
 def add_default_caacl(ca):
     root_logger.info('[Add default CA ACL]')
 
@@ -1443,6 +1468,7 @@ def upgrade_configuration():
 
     ca_restart = any([
         ca_restart,
+        ca_upgrade_schema(ca),
         upgrade_ca_audit_cert_validity(ca),
         certificate_renewal_update(ca),
         ca_enable_pkix(ca),
-- 
2.1.0

-------------- next part --------------
From c29e538ce269f31a6ac417c5288172accd2bdb11 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftweedal at redhat.com>
Date: Tue, 16 Jun 2015 07:38:06 -0400
Subject: [PATCH 22/22] Migrate CA profiles after enabling LDAPProfileSubsystem

After enabling LDAPProfileSubsystem in Dogtag, migrate the
file-based profiles into the LDAP database.
---
 ipaserver/install/cainstance.py     | 134 ++++++++++++++++++++++++++++--------
 ipaserver/install/server/upgrade.py |   7 +-
 2 files changed, 111 insertions(+), 30 deletions(-)

diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 563a198ab472a58cc6fbeeceb7731486ce7ca6b5..90e8b03754d71845c6b6335c0f2c2e3657037a26 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -1639,6 +1639,29 @@ def update_people_entry(dercert):
 
     return True
 
+def ensure_ldap_profiles_container():
+    server_id = installutils.realm_to_serverid(api.env.realm)
+    dogtag_uri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % server_id
+
+    conn = ldap2.ldap2(shared_instance=False, ldap_uri=dogtag_uri)
+    if not conn.isconnected():
+        conn.connect(autobind=True)
+
+    dn = DN(('ou', 'certificateProfiles'), ('ou', 'ca'), ('o', 'ipaca'))
+    try:
+        conn.get_entry(dn)
+    except errors.NotFound:
+        # entry doesn't exist; add it
+        entry = conn.make_entry(
+            dn,
+            objectclass=['top', 'organizationalUnit'],
+            ou=['certificateProfiles'],
+        )
+        conn.add_entry(entry)
+
+    conn.disconnect()
+
+
 def configure_profiles_acl():
     server_id = installutils.realm_to_serverid(api.env.realm)
     dogtag_uri = 'ldapi://%%2fvar%%2frun%%2fslapd-%s.socket' % server_id
@@ -1677,6 +1700,9 @@ def import_included_profiles():
     if not conn.isconnected():
         conn.connect(autobind=True)
 
+    api.Backend.ra_certprofile._read_password()
+    api.Backend.ra_certprofile.override_port = 8443
+
     for (profile_id, desc, store_issued) in dogtag.INCLUDED_PROFILES:
         dn = DN(('cn', profile_id),
             api.env.container_certprofile, api.env.basedn)
@@ -1685,9 +1711,6 @@ def import_included_profiles():
             continue  # the profile is present
         except errors.NotFound:
             # profile not found; add it
-            profile_data = ipautil.template_file(
-                '/usr/share/ipa/profiles/{}.cfg'.format(profile_id), sub_dict)
-
             entry = conn.make_entry(
                 dn,
                 objectclass=['ipacertprofile'],
@@ -1696,34 +1719,91 @@ def import_included_profiles():
                 ipacertprofilestoreissued=['TRUE' if store_issued else 'FALSE'],
             )
             conn.add_entry(entry)
-            api.Backend.ra_certprofile._read_password()
-            api.Backend.ra_certprofile.override_port = 8443
-            with api.Backend.ra_certprofile as profile_api:
-                # import the profile
-                try:
-                    profile_api.create_profile(profile_data)
-                except errors.RemoteRetrieveError:
-                    # conflicting profile; replace it if we are
-                    # installing IPA, but keep it for upgrades
-                    if api.env.context == 'installer':
-                        try:
-                            profile_api.disable_profile(profile_id)
-                        except errors.RemoteRetrieveError:
-                            pass
-                        profile_api.delete_profile(profile_id)
-                        profile_api.create_profile(profile_data)
-
-                # enable the profile
-                try:
-                    profile_api.enable_profile(profile_id)
-                except errors.RemoteRetrieveError:
-                    pass
-
-            api.Backend.ra_certprofile.override_port = None
+            profile_data = ipautil.template_file(
+                '/usr/share/ipa/profiles/{}.cfg'.format(profile_id), sub_dict)
+            _create_dogtag_profile(profile_id, profile_data)
             root_logger.info("Imported profile '%s'", profile_id)
 
+    api.Backend.ra_certprofile.override_port = None
     conn.disconnect()
 
+
+def migrate_profiles_to_ldap():
+    """Migrate profiles from filesystem to LDAP.
+
+    This must be run *after* switching to the LDAPProfileSubsystem
+    and restarting the CA.
+
+    The profile might already exist, e.g. if a replica was already
+    upgraded, so this case is ignored.
+
+    """
+    ensure_ldap_profiles_container()
+
+    api.Backend.ra_certprofile._read_password()
+    api.Backend.ra_certprofile.override_port = 8443
+
+    cs_cfg = None
+    with open(dogtag.configured_constants().CS_CFG_PATH) as f:
+        cs_cfg = f.read()
+    match = re.search(r'^profile\.list=(\S*)', cs_cfg, re.MULTILINE)
+    profile_ids = match.group(1).split(',')
+
+    print cs_cfg
+    for profile_id in profile_ids:
+        match = re.search(
+            r'^profile\.{}\.config=(\S*)'.format(profile_id),
+            cs_cfg, re.MULTILINE
+        )
+        if match is None:
+            root_logger.info("No file for profile '%s'; skipping", profile_id)
+            continue
+        filename = match.group(1)
+
+        match = re.search(
+            r'^profile\.{}\.class_id=(\S*)'.format(profile_id),
+            cs_cfg, re.MULTILINE
+        )
+        if match is None:
+            root_logger.info("No class_id for profile '%s'; skipping", profile_id)
+            continue
+        class_id = match.group(1)
+
+        root_logger.info("Migrating profile '%s' to LDAP", profile_id)
+        with open(filename) as f:
+            profile_data = f.read()
+            if profile_data[-1] != '\n':
+                profile_data += '\n'
+            profile_data += 'profileId={}\n'.format(profile_id)
+            profile_data += 'classId={}\n'.format(class_id)
+            _create_dogtag_profile(profile_id, profile_data)
+
+    api.Backend.ra_certprofile.override_port = None
+
+
+def _create_dogtag_profile(profile_id, profile_data):
+    with api.Backend.ra_certprofile as profile_api:
+        # import the profile
+        try:
+            profile_api.create_profile(profile_data)
+        except errors.RemoteRetrieveError:
+            # conflicting profile; replace it if we are
+            # installing IPA, but keep it for upgrades
+            if api.env.context == 'installer':
+                try:
+                    profile_api.disable_profile(profile_id)
+                except errors.RemoteRetrieveError:
+                    pass
+                profile_api.delete_profile(profile_id)
+                profile_api.create_profile(profile_data)
+
+        # enable the profile
+        try:
+            profile_api.enable_profile(profile_id)
+        except errors.RemoteRetrieveError:
+            pass
+
+
 if __name__ == "__main__":
     standard_logging_setup("install.log")
     ds = dsinstance.DsInstance()
diff --git a/ipaserver/install/server/upgrade.py b/ipaserver/install/server/upgrade.py
index 78a4ace82f35193652cc535423309c67bca09df4..1a4588a540e7c91fa009e14c007c16809c807a6b 100644
--- a/ipaserver/install/server/upgrade.py
+++ b/ipaserver/install/server/upgrade.py
@@ -332,8 +332,8 @@ def ca_enable_ldap_profile_subsystem(ca):
             quotes=False,
             separator='=')
 
-    # TODO import file-based profiles into Dogtag
-    # More code needed on Dogtag side for this.
+        ca.restart(dogtag.configured_constants().PKI_INSTANCE_NAME)
+        cainstance.migrate_profiles_to_ldap()
 
     return needs_update
 
@@ -1473,7 +1473,6 @@ def upgrade_configuration():
         certificate_renewal_update(ca),
         ca_enable_pkix(ca),
         ca_configure_profiles_acl(ca),
-        ca_enable_ldap_profile_subsystem(ca),
     ])
 
     if ca_restart:
@@ -1483,6 +1482,8 @@ def upgrade_configuration():
         except ipautil.CalledProcessError as e:
             root_logger.error("Failed to restart %s: %s", ca.service_name, e)
 
+    ca_enable_ldap_profile_subsystem(ca)
+
     # This step MUST be done after ca_enable_ldap_profile_subsystem and
     # ca_configure_profiles_acl, and the consequent restart, but does not
     # itself require a restart.
-- 
2.1.0



More information about the Freeipa-devel mailing list