e3ffab
From 5fa2b9d411c7c35266fa1c9726d91243ba2b02d6 Mon Sep 17 00:00:00 2001
e3ffab
From: Jan Cholasta <jcholast@redhat.com>
e3ffab
Date: Tue, 14 Oct 2014 11:12:55 +0200
e3ffab
Subject: [PATCH] Do not wait for new CA certificate to appear in LDAP in
e3ffab
 ipa-certupdate
e3ffab
e3ffab
If new certificate is not available, reuse the old one, instead of waiting
e3ffab
indefinitely for the new certificate to appear.
e3ffab
e3ffab
https://fedorahosted.org/freeipa/ticket/4628
e3ffab
e3ffab
Reviewed-By: David Kupka <dkupka@redhat.com>
e3ffab
---
e3ffab
 .../certmonger/dogtag-ipa-ca-renew-agent-submit    | 87 ++++++++++++----------
e3ffab
 ipa-client/ipaclient/ipa_certupdate.py             |  6 +-
e3ffab
 2 files changed, 53 insertions(+), 40 deletions(-)
e3ffab
e3ffab
diff --git a/install/certmonger/dogtag-ipa-ca-renew-agent-submit b/install/certmonger/dogtag-ipa-ca-renew-agent-submit
e3ffab
index ca4380c331cc417c0a89eca17e987920118337d7..9a01eb3a08900a5c8d04953b41f4493f30c2b56f 100755
e3ffab
--- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit
e3ffab
+++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit
e3ffab
@@ -279,25 +279,11 @@ def request_and_store_cert():
e3ffab
     else:
e3ffab
         return result
e3ffab
 
e3ffab
-def retrieve_cert():
e3ffab
+def retrieve_or_reuse_cert():
e3ffab
     """
e3ffab
-    Retrieve new certificate from LDAP.
e3ffab
+    Retrieve certificate from LDAP. If the certificate is not available, reuse
e3ffab
+    the old certificate.
e3ffab
     """
e3ffab
-    operation = os.environ.get('CERTMONGER_OPERATION')
e3ffab
-    if operation == 'SUBMIT':
e3ffab
-        attempts = 0
e3ffab
-    elif operation == 'POLL':
e3ffab
-        cookie = os.environ.get('CERTMONGER_CA_COOKIE')
e3ffab
-        if not cookie:
e3ffab
-            return (UNCONFIGURED, "Cookie not provided")
e3ffab
-
e3ffab
-        try:
e3ffab
-            attempts = int(cookie)
e3ffab
-        except ValueError:
e3ffab
-            return (UNCONFIGURED, "Invalid cookie: %r" % cookie)
e3ffab
-    else:
e3ffab
-        return (OPERATION_NOT_SUPPORTED_BY_HELPER,)
e3ffab
-
e3ffab
     csr = os.environ.get('CERTMONGER_CSR')
e3ffab
     if not csr:
e3ffab
         return (UNCONFIGURED, "Certificate request not provided")
e3ffab
@@ -306,12 +292,9 @@ def retrieve_cert():
e3ffab
     if not nickname:
e3ffab
         return (REJECTED, "No friendly name in the certificate request")
e3ffab
 
e3ffab
-    old_cert = os.environ.get('CERTMONGER_CERTIFICATE')
e3ffab
-    if not old_cert:
e3ffab
+    cert = os.environ.get('CERTMONGER_CERTIFICATE')
e3ffab
+    if not cert:
e3ffab
         return (REJECTED, "New certificate requests not supported")
e3ffab
-    old_cert = x509.normalize_certificate(old_cert)
e3ffab
-
e3ffab
-    syslog.syslog(syslog.LOG_NOTICE, "Updating certificate for %s" % nickname)
e3ffab
 
e3ffab
     with ldap_connect() as conn:
e3ffab
         try:
e3ffab
@@ -320,23 +303,50 @@ def retrieve_cert():
e3ffab
                    ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn),
e3ffab
                 ['usercertificate'])
e3ffab
         except errors.NotFound:
e3ffab
-            cert = old_cert
e3ffab
+            pass
e3ffab
         else:
e3ffab
             cert = entry.single_value['usercertificate']
e3ffab
+            cert = base64.b64encode(cert)
e3ffab
+            cert = x509.make_pem(cert)
e3ffab
+
e3ffab
+    return (ISSUED, cert)
e3ffab
+
e3ffab
+def retrieve_cert():
e3ffab
+    """
e3ffab
+    Retrieve new certificate from LDAP.
e3ffab
+    """
e3ffab
+    operation = os.environ.get('CERTMONGER_OPERATION')
e3ffab
+    if operation == 'SUBMIT':
e3ffab
+        attempts = 0
e3ffab
+    elif operation == 'POLL':
e3ffab
+        cookie = os.environ.get('CERTMONGER_CA_COOKIE')
e3ffab
+        if not cookie:
e3ffab
+            return (UNCONFIGURED, "Cookie not provided")
e3ffab
+
e3ffab
+        try:
e3ffab
+            attempts = int(cookie)
e3ffab
+        except ValueError:
e3ffab
+            return (UNCONFIGURED, "Invalid cookie: %r" % cookie)
e3ffab
+    else:
e3ffab
+        return (OPERATION_NOT_SUPPORTED_BY_HELPER,)
e3ffab
 
e3ffab
-        if cert == old_cert:
e3ffab
-            attempts += 1
e3ffab
-            if attempts < 4:
e3ffab
-                syslog.syslog(
e3ffab
-                    syslog.LOG_INFO,
e3ffab
-                    "Updated certificate for %s not available" % nickname)
e3ffab
-                # No cert available yet, tell certmonger to wait another 8 hours
e3ffab
-                return (WAIT_WITH_DELAY, 8 * 60 * 60, str(attempts))
e3ffab
+    old_cert = os.environ.get('CERTMONGER_CERTIFICATE')
e3ffab
+    if old_cert:
e3ffab
+        old_cert = x509.normalize_certificate(old_cert)
e3ffab
 
e3ffab
-        cert = base64.b64encode(cert)
e3ffab
-        cert = x509.make_pem(cert)
e3ffab
+    result = call_handler(retrieve_or_reuse_cert)
e3ffab
+    if result[0] != ISSUED:
e3ffab
+        return result
e3ffab
 
e3ffab
-    return (ISSUED, cert)
e3ffab
+    new_cert = x509.normalize_certificate(result[1])
e3ffab
+    if new_cert == old_cert:
e3ffab
+        attempts += 1
e3ffab
+        if attempts < 4:
e3ffab
+            syslog.syslog(syslog.LOG_INFO, "Updated certificate not available")
e3ffab
+            # No cert available yet, tell certmonger to wait another 8 hours
e3ffab
+            return (WAIT_WITH_DELAY, 8 * 60 * 60, str(attempts))
e3ffab
+
e3ffab
+    return result
e3ffab
 
e3ffab
 def export_csr():
e3ffab
     """
e3ffab
@@ -414,10 +424,11 @@ def renew_ca_cert():
e3ffab
 
e3ffab
 def main():
e3ffab
     handlers = {
e3ffab
-        'ipaStorage':       store_cert,
e3ffab
-        'ipaRetrieval':     retrieve_cert,
e3ffab
-        'ipaCSRExport':     export_csr,
e3ffab
-        'ipaCACertRenewal': renew_ca_cert,
e3ffab
+        'ipaStorage':           store_cert,
e3ffab
+        'ipaRetrievalOrReuse':  retrieve_or_reuse_cert,
e3ffab
+        'ipaRetrieval':         retrieve_cert,
e3ffab
+        'ipaCSRExport':         export_csr,
e3ffab
+        'ipaCACertRenewal':     renew_ca_cert,
e3ffab
     }
e3ffab
 
e3ffab
     api.bootstrap(context='renew')
e3ffab
diff --git a/ipa-client/ipaclient/ipa_certupdate.py b/ipa-client/ipaclient/ipa_certupdate.py
e3ffab
index 7ef11d058eeeb47dc47d46aa7cbe73578c42d131..031a34c3a54a02d43978eedcb794678a1550702b 100644
e3ffab
--- a/ipa-client/ipaclient/ipa_certupdate.py
e3ffab
+++ b/ipa-client/ipaclient/ipa_certupdate.py
e3ffab
@@ -143,14 +143,16 @@ class CertUpdate(admintool.AdminTool):
e3ffab
             timeout = api.env.startup_timeout + 60
e3ffab
 
e3ffab
             self.log.debug("resubmitting certmonger request '%s'", request_id)
e3ffab
-            certmonger.resubmit_request(request_id, profile='ipaRetrieval')
e3ffab
+            certmonger.resubmit_request(
e3ffab
+                request_id, profile='ipaRetrievalOrReuse')
e3ffab
             try:
e3ffab
                 state = certmonger.wait_for_request(request_id, timeout)
e3ffab
             except RuntimeError:
e3ffab
                 raise admintool.ScriptError(
e3ffab
                     "Resubmitting certmonger request '%s' timed out, "
e3ffab
                     "please check the request manually" % request_id)
e3ffab
-            if state != 'MONITORING':
e3ffab
+            ca_error = certmonger.get_request_value(request_id, 'ca-error')
e3ffab
+            if state != 'MONITORING' or ca_error:
e3ffab
                 raise admintool.ScriptError(
e3ffab
                     "Error resubmitting certmonger request '%s', "
e3ffab
                     "please check the request manually" % request_id)
e3ffab
-- 
e3ffab
2.1.0
e3ffab