URL: https://github.com/freeipa/freeipa/pull/1310
Author: tiran
 Title: #1310: 6577 ca replica install certupdate2
Action: opened

PR body:
"""

"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/1310/head:pr1310
git checkout pr1310
From 9520781fb5d198f274cf7ccadec5c434ada69535 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftwee...@redhat.com>
Date: Mon, 30 Oct 2017 17:52:07 +1100
Subject: [PATCH 1/4] CertUpdate: make it easy to invoke from other programs

The guts of ipa-certupdate are useful to execute as part of other
programs (e.g. as a first step of ipa-ca-install).  Refactor
ipa_certupdate.CertUpdate to make it easy to do that.  In
particular, make it possible to use an already-initialised API
object.

Part of: https://pagure.io/freeipa/issue/6577
---
 ipaclient/install/ipa_certupdate.py | 63 ++++++++++++++++++++++---------------
 1 file changed, 38 insertions(+), 25 deletions(-)

diff --git a/ipaclient/install/ipa_certupdate.py b/ipaclient/install/ipa_certupdate.py
index 06fd079226..32407ad967 100644
--- a/ipaclient/install/ipa_certupdate.py
+++ b/ipaclient/install/ipa_certupdate.py
@@ -56,30 +56,36 @@ def run(self):
         api.bootstrap(context='cli_installer', confdir=paths.ETC_IPA)
         api.finalize()
 
+        api.Backend.rpcclient.connect()
+        self.run_with_api(api)
+        api.Backend.rpcclient.disconnect()
+
+    @classmethod
+    def run_with_api(cls, api):
+        """
+        Run the certupdate procedure with the given API object.
+
+        :param api: API object with ldap2/rpcclient backend connected
+                    (such that Commands can be invoked)
+
+        """
         server = urlsplit(api.env.jsonrpc_uri).hostname
         ldap_uri = ipaldap.get_ldap_uri(server)
         ldap = ipaldap.LDAPClient(ldap_uri)
 
         tmpdir = tempfile.mkdtemp(prefix="tmp-")
         ccache_name = os.path.join(tmpdir, 'ccache')
+        old_krb5ccname = os.environ.get('KRB5CCNAME')
         try:
             principal = str('host/%s@%s' % (api.env.host, api.env.realm))
             kinit_keytab(principal, paths.KRB5_KEYTAB, ccache_name)
             os.environ['KRB5CCNAME'] = ccache_name
 
-            api.Backend.rpcclient.connect()
             try:
-                result = api.Backend.rpcclient.forward(
-                    'ca_is_enabled',
-                    version=u'2.107',
-                )
+                result = api.Command.ca_is_enabled(version=u'2.107')
                 ca_enabled = result['result']
             except (errors.CommandError, errors.NetworkError):
-                result = api.Backend.rpcclient.forward(
-                    'env',
-                    server=True,
-                    version=u'2.0',
-                )
+                result = api.Command.env(server=True, version=u'2.0')
                 ca_enabled = result['result']['enable_ra']
 
             ldap.gssapi_bind()
@@ -92,13 +98,16 @@ def run(self):
             else:
                 lwcas = []
 
-            api.Backend.rpcclient.disconnect()
         finally:
+            if old_krb5ccname is None:
+                del os.environ['KRB5CCNAME']
+            else:
+                os.environ['KRB5CCNAME'] = old_krb5ccname
             shutil.rmtree(tmpdir)
 
         server_fstore = sysrestore.FileStore(paths.SYSRESTORE)
         if server_fstore.has_files():
-            self.update_server(certs)
+            cls.update_server(certs)
             try:
                 # pylint: disable=import-error,ipa-forbidden-import
                 from ipaserver.install import cainstance
@@ -108,12 +117,13 @@ def run(self):
                 logger.exception(
                     "Failed to add lightweight CA tracking requests")
 
-        self.update_client(certs)
+        cls.update_client(certs)
 
-    def update_client(self, certs):
-        self.update_file(paths.IPA_CA_CRT, certs)
-        self.update_file(paths.KDC_CA_BUNDLE_PEM, certs)
-        self.update_file(paths.CA_BUNDLE_PEM, certs)
+    @classmethod
+    def update_client(cls, certs):
+        cls.update_file(paths.IPA_CA_CRT, certs)
+        cls.update_file(paths.KDC_CA_BUNDLE_PEM, certs)
+        cls.update_file(paths.CA_BUNDLE_PEM, certs)
 
         ipa_db = certdb.NSSDatabase(api.env.nss_dir)
 
@@ -127,19 +137,20 @@ def update_client(self, certs):
                                  nickname, ipa_db.secdir, e)
                     break
 
-        self.update_db(ipa_db.secdir, certs)
+        cls.update_db(ipa_db.secdir, certs)
 
         tasks.remove_ca_certs_from_systemwide_ca_store()
         tasks.insert_ca_certs_into_systemwide_ca_store(certs)
 
-    def update_server(self, certs):
+    @classmethod
+    def update_server(cls, certs):
         instance = '-'.join(api.env.realm.split('.'))
-        self.update_db(
+        cls.update_db(
             paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % instance, certs)
         if services.knownservices.dirsrv.is_running():
             services.knownservices.dirsrv.restart(instance)
 
-        self.update_db(paths.HTTPD_ALIAS_DIR, certs)
+        cls.update_db(paths.HTTPD_ALIAS_DIR, certs)
         if services.knownservices.httpd.is_running():
             services.knownservices.httpd.restart()
 
@@ -170,17 +181,19 @@ def update_server(self, certs):
             logger.debug("modifying certmonger request '%s'", request_id)
             certmonger.modify(request_id, ca='dogtag-ipa-ca-renew-agent')
 
-        self.update_file(paths.CA_CRT, certs)
-        self.update_file(paths.CACERT_PEM, certs)
+        cls.update_file(paths.CA_CRT, certs)
+        cls.update_file(paths.CACERT_PEM, certs)
 
-    def update_file(self, filename, certs, mode=0o444):
+    @staticmethod
+    def update_file(filename, certs, mode=0o444):
         certs = (c[0] for c in certs if c[2] is not False)
         try:
             x509.write_certificate_list(certs, filename)
         except Exception as e:
             logger.error("failed to update %s: %s", filename, e)
 
-    def update_db(self, path, certs):
+    @staticmethod
+    def update_db(path, certs):
         db = certdb.NSSDatabase(path)
         for cert, nickname, trusted, eku in certs:
             trust_flags = certstore.key_policy_to_trust_flags(

From 21fbf7088f9c129f77d7308186e295e2a486c1da Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftwee...@redhat.com>
Date: Mon, 30 Oct 2017 18:05:56 +1100
Subject: [PATCH 2/4] ipa-ca-install: run certupdate as initial step

When installing a CA replica, perform a certupdate to ensure that
the relevant CA cert is present.  This is necessary if the admin has
just promoted the topology from CA-less to CA-ful but didn't
manually run ipa-certupdate afterwards.

Fixes: https://pagure.io/freeipa/issue/6577
---
 install/tools/ipa-ca-install | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install
index 64478bb0e8..498a5cf114 100755
--- a/install/tools/ipa-ca-install
+++ b/install/tools/ipa-ca-install
@@ -27,6 +27,7 @@ import tempfile
 from ipalib.install.kinit import kinit_keytab
 from ipapython import ipautil
 
+from ipaclient.install.ipa_certupdate import CertUpdate
 from ipaserver.install import installutils
 from ipaserver.install.installutils import create_replica_config
 from ipaserver.install.installutils import check_creds, ReplicaConfig
@@ -174,6 +175,16 @@ def install_replica(safe_options, options, filename):
             not options.skip_conncheck and options.unattended):
         sys.exit('admin password required')
 
+    # Run ipa-certupdate to ensure we have the CA cert.  This is
+    # necessary if the admin has just promoted the topology from
+    # CA-less to CA-ful, and ipa-certupdate has not been run yet.
+    CertUpdate.run_with_api(api)
+
+    # CertUpdate restarts DS causing broken pipe on the original
+    # connection, so reconnect the backend.
+    api.Backend.ldap2.disconnect()
+    api.Backend.ldap2.connect()
+
     if options.promote:
         config = ReplicaConfig()
         config.ca_host_name = None

From a9ad3b5ab72a12144e936faf4bc7160fc10ee209 Mon Sep 17 00:00:00 2001
From: Fraser Tweedale <ftwee...@redhat.com>
Date: Tue, 31 Oct 2017 18:20:15 +1100
Subject: [PATCH 3/4] Run certupdate after promoting to CA-ful deployment

After installing a CA in a CA-less installations (using
ipa-ca-install), the new CA certificate is not installed in
/etc/httpd/alias. This causes communication failure between IPA
framework and Dogtag (it cannot verify the Dogtag server
certificate).

Perform a CertUpdate as the final step when promoting a CA-less
deployment to CA-ful.

Fixes: https://pagure.io/freeipa/issue/7230
---
 install/tools/ipa-ca-install | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install
index 498a5cf114..65d0b38f65 100755
--- a/install/tools/ipa-ca-install
+++ b/install/tools/ipa-ca-install
@@ -254,6 +254,10 @@ def install_master(safe_options, options):
     ca.install_check(True, None, options)
     ca.install(True, None, options)
 
+    # Run ipa-certupdate to add the new CA certificate to
+    # certificate databases on this server.
+    logger.info("Updating certificate databases.")
+    CertUpdate.run_with_api(api)
 
 def install(safe_options, options, filename):
     options.promote = False

From 3f368b74d93fe66ef460c3ba225b3ae1e1c05695 Mon Sep 17 00:00:00 2001
From: Christian Heimes <chei...@redhat.com>
Date: Tue, 21 Nov 2017 09:05:51 +0100
Subject: [PATCH 4/4] No class/static methods

---
 install/tools/ipa-ca-install        |  5 ++--
 ipaclient/install/ipa_certupdate.py | 56 +++++++++++++++++--------------------
 ipapython/admintool.py              |  3 +-
 3 files changed, 30 insertions(+), 34 deletions(-)

diff --git a/install/tools/ipa-ca-install b/install/tools/ipa-ca-install
index 65d0b38f65..4eaa96bd9f 100755
--- a/install/tools/ipa-ca-install
+++ b/install/tools/ipa-ca-install
@@ -178,7 +178,7 @@ def install_replica(safe_options, options, filename):
     # Run ipa-certupdate to ensure we have the CA cert.  This is
     # necessary if the admin has just promoted the topology from
     # CA-less to CA-ful, and ipa-certupdate has not been run yet.
-    CertUpdate.run_with_api(api)
+    CertUpdate(None, None).run()
 
     # CertUpdate restarts DS causing broken pipe on the original
     # connection, so reconnect the backend.
@@ -257,7 +257,8 @@ def install_master(safe_options, options):
     # Run ipa-certupdate to add the new CA certificate to
     # certificate databases on this server.
     logger.info("Updating certificate databases.")
-    CertUpdate.run_with_api(api)
+    CertUpdate(None, None).run()
+
 
 def install(safe_options, options, filename):
     options.promote = False
diff --git a/ipaclient/install/ipa_certupdate.py b/ipaclient/install/ipa_certupdate.py
index 32407ad967..1b1396013e 100644
--- a/ipaclient/install/ipa_certupdate.py
+++ b/ipaclient/install/ipa_certupdate.py
@@ -51,24 +51,16 @@ def validate_options(self):
         super(CertUpdate, self).validate_options(needs_root=True)
 
     def run(self):
-        check_client_configuration()
-
-        api.bootstrap(context='cli_installer', confdir=paths.ETC_IPA)
-        api.finalize()
-
-        api.Backend.rpcclient.connect()
-        self.run_with_api(api)
-        api.Backend.rpcclient.disconnect()
-
-    @classmethod
-    def run_with_api(cls, api):
         """
         Run the certupdate procedure with the given API object.
+        """
+        check_client_configuration()
 
-        :param api: API object with ldap2/rpcclient backend connected
-                    (such that Commands can be invoked)
+        if not api.isdone('finalize'):
+            api.bootstrap(context='cli_installer', confdir=paths.ETC_IPA)
+            api.finalize()
+        connected = api.Backend.rpcclient.isconnected()
 
-        """
         server = urlsplit(api.env.jsonrpc_uri).hostname
         ldap_uri = ipaldap.get_ldap_uri(server)
         ldap = ipaldap.LDAPClient(ldap_uri)
@@ -81,6 +73,9 @@ def run_with_api(cls, api):
             kinit_keytab(principal, paths.KRB5_KEYTAB, ccache_name)
             os.environ['KRB5CCNAME'] = ccache_name
 
+            if not connected:
+                api.Backend.rpcclient.connect()
+
             try:
                 result = api.Command.ca_is_enabled(version=u'2.107')
                 ca_enabled = result['result']
@@ -104,10 +99,12 @@ def run_with_api(cls, api):
             else:
                 os.environ['KRB5CCNAME'] = old_krb5ccname
             shutil.rmtree(tmpdir)
+            if not connected:
+                api.Backend.rpcclient.disconnect()
 
         server_fstore = sysrestore.FileStore(paths.SYSRESTORE)
         if server_fstore.has_files():
-            cls.update_server(certs)
+            self.update_server(certs)
             try:
                 # pylint: disable=import-error,ipa-forbidden-import
                 from ipaserver.install import cainstance
@@ -117,13 +114,12 @@ def run_with_api(cls, api):
                 logger.exception(
                     "Failed to add lightweight CA tracking requests")
 
-        cls.update_client(certs)
+        self.update_client(certs)
 
-    @classmethod
-    def update_client(cls, certs):
-        cls.update_file(paths.IPA_CA_CRT, certs)
-        cls.update_file(paths.KDC_CA_BUNDLE_PEM, certs)
-        cls.update_file(paths.CA_BUNDLE_PEM, certs)
+    def update_client(self, certs):
+        self.update_file(paths.IPA_CA_CRT, certs)
+        self.update_file(paths.KDC_CA_BUNDLE_PEM, certs)
+        self.update_file(paths.CA_BUNDLE_PEM, certs)
 
         ipa_db = certdb.NSSDatabase(api.env.nss_dir)
 
@@ -137,20 +133,20 @@ def update_client(cls, certs):
                                  nickname, ipa_db.secdir, e)
                     break
 
-        cls.update_db(ipa_db.secdir, certs)
+        self.update_db(ipa_db.secdir, certs)
 
         tasks.remove_ca_certs_from_systemwide_ca_store()
         tasks.insert_ca_certs_into_systemwide_ca_store(certs)
 
     @classmethod
-    def update_server(cls, certs):
+    def update_server(self, certs):
         instance = '-'.join(api.env.realm.split('.'))
-        cls.update_db(
+        self.update_db(
             paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % instance, certs)
         if services.knownservices.dirsrv.is_running():
             services.knownservices.dirsrv.restart(instance)
 
-        cls.update_db(paths.HTTPD_ALIAS_DIR, certs)
+        self.update_db(paths.HTTPD_ALIAS_DIR, certs)
         if services.knownservices.httpd.is_running():
             services.knownservices.httpd.restart()
 
@@ -181,19 +177,17 @@ def update_server(cls, certs):
             logger.debug("modifying certmonger request '%s'", request_id)
             certmonger.modify(request_id, ca='dogtag-ipa-ca-renew-agent')
 
-        cls.update_file(paths.CA_CRT, certs)
-        cls.update_file(paths.CACERT_PEM, certs)
+        self.update_file(paths.CA_CRT, certs)
+        self.update_file(paths.CACERT_PEM, certs)
 
-    @staticmethod
-    def update_file(filename, certs, mode=0o444):
+    def update_file(self,filename, certs, mode=0o444):
         certs = (c[0] for c in certs if c[2] is not False)
         try:
             x509.write_certificate_list(certs, filename)
         except Exception as e:
             logger.error("failed to update %s: %s", filename, e)
 
-    @staticmethod
-    def update_db(path, certs):
+    def update_db(self, path, certs):
         db = certdb.NSSDatabase(path)
         for cert, nickname, trusted, eku in certs:
             trust_flags = certstore.key_policy_to_trust_flags(
diff --git a/ipapython/admintool.py b/ipapython/admintool.py
index 329e20f374..a1cd198a80 100644
--- a/ipapython/admintool.py
+++ b/ipapython/admintool.py
@@ -157,7 +157,8 @@ def get_command_class(cls, options, args):
     def __init__(self, options, args):
         self.options = options
         self.args = args
-        self.safe_options = self.option_parser.get_safe_opts(options)
+        if args is None:
+            self.safe_options = self.option_parser.get_safe_opts(options)
 
     def execute(self):
         """Do everything needed after options are parsed
_______________________________________________
FreeIPA-devel mailing list -- freeipa-devel@lists.fedorahosted.org
To unsubscribe send an email to freeipa-devel-le...@lists.fedorahosted.org

Reply via email to