|
|
e3ffab |
From b82f0b1bc483fe265f3e2d2089b65185cafffd74 Mon Sep 17 00:00:00 2001
|
|
|
e3ffab |
From: Jan Cholasta <jcholast@redhat.com>
|
|
|
e3ffab |
Date: Tue, 14 Oct 2014 10:30:07 +0200
|
|
|
e3ffab |
Subject: [PATCH] Handle profile changes in dogtag-ipa-ca-renew-agent
|
|
|
e3ffab |
|
|
|
e3ffab |
To update the CA certificate in the Dogtag NSS database, the
|
|
|
e3ffab |
"ipa-cacert-manage renew" and "ipa-certupdate" commands temporarily change
|
|
|
e3ffab |
the profile of the CA certificate certmonger request, resubmit it and
|
|
|
e3ffab |
change the profile back to the original one.
|
|
|
e3ffab |
|
|
|
e3ffab |
When something goes wrong while resubmitting the request, it needs to be
|
|
|
e3ffab |
modified and resubmitted again manually. This might fail with invalid
|
|
|
e3ffab |
cookie error, because changing the profile does not change the internal
|
|
|
e3ffab |
state of the request.
|
|
|
e3ffab |
|
|
|
e3ffab |
Detect this in dogtag-ipa-ca-renew-agent and reset the internal state when
|
|
|
e3ffab |
profile is changed.
|
|
|
e3ffab |
|
|
|
e3ffab |
https://fedorahosted.org/freeipa/ticket/4627
|
|
|
e3ffab |
|
|
|
e3ffab |
Reviewed-By: David Kupka <dkupka@redhat.com>
|
|
|
e3ffab |
---
|
|
|
e3ffab |
.../certmonger/dogtag-ipa-ca-renew-agent-submit | 87 ++++++++++++++++++++--
|
|
|
e3ffab |
1 file changed, 80 insertions(+), 7 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 4f0b78accac6840471f8b2e9f17288b3b4e82105..ca4380c331cc417c0a89eca17e987920118337d7 100755
|
|
|
e3ffab |
--- a/install/certmonger/dogtag-ipa-ca-renew-agent-submit
|
|
|
e3ffab |
+++ b/install/certmonger/dogtag-ipa-ca-renew-agent-submit
|
|
|
e3ffab |
@@ -31,6 +31,7 @@ import tempfile
|
|
|
e3ffab |
import shutil
|
|
|
e3ffab |
import base64
|
|
|
e3ffab |
import contextlib
|
|
|
e3ffab |
+import json
|
|
|
e3ffab |
|
|
|
e3ffab |
from ipapython import ipautil
|
|
|
e3ffab |
from ipapython.dn import DN
|
|
|
e3ffab |
@@ -64,6 +65,78 @@ def ldap_connect():
|
|
|
e3ffab |
if conn is not None and conn.isconnected():
|
|
|
e3ffab |
conn.disconnect()
|
|
|
e3ffab |
|
|
|
e3ffab |
+def call_handler(_handler, *args, **kwargs):
|
|
|
e3ffab |
+ """
|
|
|
e3ffab |
+ Request handler call wrapper
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ Before calling the handler, get the original profile name and cookie from
|
|
|
e3ffab |
+ the provided cookie, if there is one. If the profile name does not match
|
|
|
e3ffab |
+ the requested profile name, drop the cookie and restart the request.
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ After calling the handler, put the requested profile name and cookie
|
|
|
e3ffab |
+ returned by the handler in a new cookie and return it.
|
|
|
e3ffab |
+ """
|
|
|
e3ffab |
+ operation = os.environ['CERTMONGER_OPERATION']
|
|
|
e3ffab |
+ if operation == 'POLL':
|
|
|
e3ffab |
+ cookie = os.environ.pop('CERTMONGER_CA_COOKIE', None)
|
|
|
e3ffab |
+ if cookie is not None:
|
|
|
e3ffab |
+ try:
|
|
|
e3ffab |
+ context = json.loads(cookie)
|
|
|
e3ffab |
+ if not isinstance(context, dict):
|
|
|
e3ffab |
+ raise TypeError
|
|
|
e3ffab |
+ except (TypeError, ValueError):
|
|
|
e3ffab |
+ return (UNCONFIGURED, "Invalid cookie: %r" % cookie)
|
|
|
e3ffab |
+ else:
|
|
|
e3ffab |
+ return (UNCONFIGURED, "Cookie not provided")
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ if 'profile' in context:
|
|
|
e3ffab |
+ profile = context.pop('profile')
|
|
|
e3ffab |
+ try:
|
|
|
e3ffab |
+ if profile is not None:
|
|
|
e3ffab |
+ if not isinstance(profile, unicode):
|
|
|
e3ffab |
+ raise TypeError
|
|
|
e3ffab |
+ profile = profile.encode('raw_unicode_escape')
|
|
|
e3ffab |
+ except (TypeError, UnicodeEncodeError):
|
|
|
e3ffab |
+ return (UNCONFIGURED,
|
|
|
e3ffab |
+ "Invalid 'profile' in cookie: %r" % profile)
|
|
|
e3ffab |
+ else:
|
|
|
e3ffab |
+ return (UNCONFIGURED, "No 'profile' in cookie")
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ # If profile has changed between SUBMIT and POLL, restart request
|
|
|
e3ffab |
+ if os.environ.get('CERTMONGER_CA_PROFILE') != profile:
|
|
|
e3ffab |
+ os.environ['CERTMONGER_OPERATION'] = 'SUBMIT'
|
|
|
e3ffab |
+ context = {}
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ if 'cookie' in context:
|
|
|
e3ffab |
+ cookie = context.pop('cookie')
|
|
|
e3ffab |
+ try:
|
|
|
e3ffab |
+ if not isinstance(cookie, unicode):
|
|
|
e3ffab |
+ raise TypeError
|
|
|
e3ffab |
+ cookie = cookie.encode('raw_unicode_escape')
|
|
|
e3ffab |
+ except (TypeError, UnicodeEncodeError):
|
|
|
e3ffab |
+ return (UNCONFIGURED,
|
|
|
e3ffab |
+ "Invalid 'cookie' in cookie: %r" % cookie)
|
|
|
e3ffab |
+ os.environ['CERTMONGER_CA_COOKIE'] = cookie
|
|
|
e3ffab |
+ else:
|
|
|
e3ffab |
+ context = {}
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ result = _handler(*args, **kwargs)
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ if result[0] in (WAIT, WAIT_WITH_DELAY):
|
|
|
e3ffab |
+ context['cookie'] = result[-1].decode('raw_unicode_escape')
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ profile = os.environ.get('CERTMONGER_CA_PROFILE')
|
|
|
e3ffab |
+ if profile is not None:
|
|
|
e3ffab |
+ profile = profile.decode('raw_unicode_escape')
|
|
|
e3ffab |
+ context['profile'] = profile
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ cookie = json.dumps(context)
|
|
|
e3ffab |
+ os.environ['CERTMONGER_CA_COOKIE'] = cookie
|
|
|
e3ffab |
+ if result[0] in (WAIT, WAIT_WITH_DELAY):
|
|
|
e3ffab |
+ result = result[:-1] + (cookie,)
|
|
|
e3ffab |
+
|
|
|
e3ffab |
+ return result
|
|
|
e3ffab |
+
|
|
|
e3ffab |
def request_cert():
|
|
|
e3ffab |
"""
|
|
|
e3ffab |
Request certificate from IPA CA.
|
|
|
e3ffab |
@@ -144,7 +217,7 @@ def store_cert():
|
|
|
e3ffab |
syslog.syslog(
|
|
|
e3ffab |
syslog.LOG_ERR,
|
|
|
e3ffab |
"Updating renewal certificate failed: %s. Sleeping 30s" % e)
|
|
|
e3ffab |
- return (WAIT_WITH_DELAY, 30, attempts)
|
|
|
e3ffab |
+ return (WAIT_WITH_DELAY, 30, str(attempts))
|
|
|
e3ffab |
else:
|
|
|
e3ffab |
syslog.syslog(
|
|
|
e3ffab |
syslog.LOG_ERR,
|
|
|
e3ffab |
@@ -179,7 +252,7 @@ def request_and_store_cert():
|
|
|
e3ffab |
else:
|
|
|
e3ffab |
os.environ['CERTMONGER_CA_COOKIE'] = cookie
|
|
|
e3ffab |
|
|
|
e3ffab |
- result = request_cert()
|
|
|
e3ffab |
+ result = call_handler(request_cert)
|
|
|
e3ffab |
if result[0] == WAIT:
|
|
|
e3ffab |
return (result[0], 'request:%s' % result[1])
|
|
|
e3ffab |
elif result[0] == WAIT_WITH_DELAY:
|
|
|
e3ffab |
@@ -198,7 +271,7 @@ def request_and_store_cert():
|
|
|
e3ffab |
os.environ['CERTMONGER_CA_COOKIE'] = cookie
|
|
|
e3ffab |
os.environ['CERTMONGER_CERTIFICATE'] = cert
|
|
|
e3ffab |
|
|
|
e3ffab |
- result = store_cert()
|
|
|
e3ffab |
+ result = call_handler(store_cert)
|
|
|
e3ffab |
if result[0] == WAIT:
|
|
|
e3ffab |
return (result[0], 'store:%s:%s' % (cert, result[1]))
|
|
|
e3ffab |
elif result[0] == WAIT_WITH_DELAY:
|
|
|
e3ffab |
@@ -258,7 +331,7 @@ def retrieve_cert():
|
|
|
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, attempts)
|
|
|
e3ffab |
+ return (WAIT_WITH_DELAY, 8 * 60 * 60, str(attempts))
|
|
|
e3ffab |
|
|
|
e3ffab |
cert = base64.b64encode(cert)
|
|
|
e3ffab |
cert = x509.make_pem(cert)
|
|
|
e3ffab |
@@ -323,14 +396,14 @@ def renew_ca_cert():
|
|
|
e3ffab |
return (OPERATION_NOT_SUPPORTED_BY_HELPER,)
|
|
|
e3ffab |
|
|
|
e3ffab |
if state == 'retrieve':
|
|
|
e3ffab |
- result = retrieve_cert()
|
|
|
e3ffab |
+ result = call_handler(retrieve_cert)
|
|
|
e3ffab |
if result[0] == WAIT_WITH_DELAY and not is_self_signed:
|
|
|
e3ffab |
syslog.syslog(syslog.LOG_ALERT,
|
|
|
e3ffab |
"IPA CA certificate is about to expire, "
|
|
|
e3ffab |
"use ipa-cacert-manage to renew it")
|
|
|
e3ffab |
elif state == 'request':
|
|
|
e3ffab |
os.environ['CERTMONGER_CA_PROFILE'] = 'caCACert'
|
|
|
e3ffab |
- result = request_and_store_cert()
|
|
|
e3ffab |
+ result = call_handler(request_and_store_cert)
|
|
|
e3ffab |
|
|
|
e3ffab |
if result[0] == WAIT:
|
|
|
e3ffab |
return (result[0], '%s:%s' % (state, result[1]))
|
|
|
e3ffab |
@@ -369,7 +442,7 @@ def main():
|
|
|
e3ffab |
else:
|
|
|
e3ffab |
handler = retrieve_cert
|
|
|
e3ffab |
|
|
|
e3ffab |
- res = handler()
|
|
|
e3ffab |
+ res = call_handler(handler)
|
|
|
e3ffab |
for item in res[1:]:
|
|
|
e3ffab |
print item
|
|
|
e3ffab |
return res[0]
|
|
|
e3ffab |
--
|
|
|
e3ffab |
2.1.0
|
|
|
e3ffab |
|