Blob Blame History Raw
From 5fa2b9d411c7c35266fa1c9726d91243ba2b02d6 Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jcholast@redhat.com>
Date: Tue, 14 Oct 2014 11:12:55 +0200
Subject: [PATCH] Do not wait for new CA certificate to appear in LDAP in
 ipa-certupdate

If new certificate is not available, reuse the old one, instead of waiting
indefinitely for the new certificate to appear.

https://fedorahosted.org/freeipa/ticket/4628

Reviewed-By: David Kupka <dkupka@redhat.com>
---
 .../certmonger/dogtag-ipa-ca-renew-agent-submit    | 87 ++++++++++++----------
 ipa-client/ipaclient/ipa_certupdate.py             |  6 +-
 2 files changed, 53 insertions(+), 40 deletions(-)

diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit
index ca4380c331cc417c0a89eca17e987920118337d7..9a01eb3a08900a5c8d04953b41f4493f30c2b56f 100755
--- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit
+++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit
@@ -279,25 +279,11 @@ def request_and_store_cert():
     else:
         return result
 
-def retrieve_cert():
+def retrieve_or_reuse_cert():
     """
-    Retrieve new certificate from LDAP.
+    Retrieve certificate from LDAP. If the certificate is not available, reuse
+    the old certificate.
     """
-    operation = os.environ.get('CERTMONGER_OPERATION')
-    if operation == 'SUBMIT':
-        attempts = 0
-    elif operation == 'POLL':
-        cookie = os.environ.get('CERTMONGER_CA_COOKIE')
-        if not cookie:
-            return (UNCONFIGURED, "Cookie not provided")
-
-        try:
-            attempts = int(cookie)
-        except ValueError:
-            return (UNCONFIGURED, "Invalid cookie: %r" % cookie)
-    else:
-        return (OPERATION_NOT_SUPPORTED_BY_HELPER,)
-
     csr = os.environ.get('CERTMONGER_CSR')
     if not csr:
         return (UNCONFIGURED, "Certificate request not provided")
@@ -306,12 +292,9 @@ def retrieve_cert():
     if not nickname:
         return (REJECTED, "No friendly name in the certificate request")
 
-    old_cert = os.environ.get('CERTMONGER_CERTIFICATE')
-    if not old_cert:
+    cert = os.environ.get('CERTMONGER_CERTIFICATE')
+    if not cert:
         return (REJECTED, "New certificate requests not supported")
-    old_cert = x509.normalize_certificate(old_cert)
-
-    syslog.syslog(syslog.LOG_NOTICE, "Updating certificate for %s" % nickname)
 
     with ldap_connect() as conn:
         try:
@@ -320,23 +303,50 @@ def retrieve_cert():
                    ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn),
                 ['usercertificate'])
         except errors.NotFound:
-            cert = old_cert
+            pass
         else:
             cert = entry.single_value['usercertificate']
+            cert = base64.b64encode(cert)
+            cert = x509.make_pem(cert)
+
+    return (ISSUED, cert)
+
+def retrieve_cert():
+    """
+    Retrieve new certificate from LDAP.
+    """
+    operation = os.environ.get('CERTMONGER_OPERATION')
+    if operation == 'SUBMIT':
+        attempts = 0
+    elif operation == 'POLL':
+        cookie = os.environ.get('CERTMONGER_CA_COOKIE')
+        if not cookie:
+            return (UNCONFIGURED, "Cookie not provided")
+
+        try:
+            attempts = int(cookie)
+        except ValueError:
+            return (UNCONFIGURED, "Invalid cookie: %r" % cookie)
+    else:
+        return (OPERATION_NOT_SUPPORTED_BY_HELPER,)
 
-        if cert == old_cert:
-            attempts += 1
-            if attempts < 4:
-                syslog.syslog(
-                    syslog.LOG_INFO,
-                    "Updated certificate for %s not available" % nickname)
-                # No cert available yet, tell certmonger to wait another 8 hours
-                return (WAIT_WITH_DELAY, 8 * 60 * 60, str(attempts))
+    old_cert = os.environ.get('CERTMONGER_CERTIFICATE')
+    if old_cert:
+        old_cert = x509.normalize_certificate(old_cert)
 
-        cert = base64.b64encode(cert)
-        cert = x509.make_pem(cert)
+    result = call_handler(retrieve_or_reuse_cert)
+    if result[0] != ISSUED:
+        return result
 
-    return (ISSUED, cert)
+    new_cert = x509.normalize_certificate(result[1])
+    if new_cert == old_cert:
+        attempts += 1
+        if attempts < 4:
+            syslog.syslog(syslog.LOG_INFO, "Updated certificate not available")
+            # No cert available yet, tell certmonger to wait another 8 hours
+            return (WAIT_WITH_DELAY, 8 * 60 * 60, str(attempts))
+
+    return result
 
 def export_csr():
     """
@@ -414,10 +424,11 @@ def renew_ca_cert():
 
 def main():
     handlers = {
-        'ipaStorage':       store_cert,
-        'ipaRetrieval':     retrieve_cert,
-        'ipaCSRExport':     export_csr,
-        'ipaCACertRenewal': renew_ca_cert,
+        'ipaStorage':           store_cert,
+        'ipaRetrievalOrReuse':  retrieve_or_reuse_cert,
+        'ipaRetrieval':         retrieve_cert,
+        'ipaCSRExport':         export_csr,
+        'ipaCACertRenewal':     renew_ca_cert,
     }
 
     api.bootstrap(context='renew')
diff --git a/ipa-client/ipaclient/ipa_certupdate.py b/ipa-client/ipaclient/ipa_certupdate.py
index 7ef11d058eeeb47dc47d46aa7cbe73578c42d131..031a34c3a54a02d43978eedcb794678a1550702b 100644
--- a/ipa-client/ipaclient/ipa_certupdate.py
+++ b/ipa-client/ipaclient/ipa_certupdate.py
@@ -143,14 +143,16 @@ class CertUpdate(admintool.AdminTool):
             timeout = api.env.startup_timeout + 60
 
             self.log.debug("resubmitting certmonger request '%s'", request_id)
-            certmonger.resubmit_request(request_id, profile='ipaRetrieval')
+            certmonger.resubmit_request(
+                request_id, profile='ipaRetrievalOrReuse')
             try:
                 state = certmonger.wait_for_request(request_id, timeout)
             except RuntimeError:
                 raise admintool.ScriptError(
                     "Resubmitting certmonger request '%s' timed out, "
                     "please check the request manually" % request_id)
-            if state != 'MONITORING':
+            ca_error = certmonger.get_request_value(request_id, 'ca-error')
+            if state != 'MONITORING' or ca_error:
                 raise admintool.ScriptError(
                     "Error resubmitting certmonger request '%s', "
                     "please check the request manually" % request_id)
-- 
2.1.0