|
|
ac7d03 |
From eb9d14debc4276f422ae55d141e30246d5943067 Mon Sep 17 00:00:00 2001
|
|
|
ac7d03 |
From: Jan Cholasta <jcholast@redhat.com>
|
|
|
ac7d03 |
Date: Thu, 30 Mar 2017 08:33:30 +0000
|
|
|
ac7d03 |
Subject: [PATCH] cert: defer cert-find result post-processing
|
|
|
ac7d03 |
|
|
|
ac7d03 |
Rather than post-processing the results of each internal search,
|
|
|
ac7d03 |
post-process the combined result.
|
|
|
ac7d03 |
|
|
|
ac7d03 |
This avoids expensive per-certificate searches when cert-find is executed
|
|
|
ac7d03 |
with the --all option on certificates which won't even be included in the
|
|
|
ac7d03 |
combined result.
|
|
|
ac7d03 |
|
|
|
ac7d03 |
https://pagure.io/freeipa/issue/6808
|
|
|
ac7d03 |
|
|
|
ac7d03 |
Reviewed-By: Stanislav Laznicka <slaznick@redhat.com>
|
|
|
ac7d03 |
---
|
|
|
ac7d03 |
ipaserver/plugins/cert.py | 93 +++++++++++++++++++++++++++------------------
|
|
|
ac7d03 |
ipaserver/plugins/dogtag.py | 10 +++++
|
|
|
ac7d03 |
2 files changed, 66 insertions(+), 37 deletions(-)
|
|
|
ac7d03 |
|
|
|
ac7d03 |
diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py
|
|
|
ac7d03 |
index dfc7444ddbf31ac3c194e050af28220fc2a87a92..68402679cf0320e9c664ea89276f6c4332730a15 100644
|
|
|
ac7d03 |
--- a/ipaserver/plugins/cert.py
|
|
|
ac7d03 |
+++ b/ipaserver/plugins/cert.py
|
|
|
ac7d03 |
@@ -162,6 +162,11 @@ def normalize_pkidate(value):
|
|
|
ac7d03 |
return datetime.datetime.strptime(value, PKIDATE_FORMAT)
|
|
|
ac7d03 |
|
|
|
ac7d03 |
|
|
|
ac7d03 |
+def convert_pkidatetime(value):
|
|
|
ac7d03 |
+ value = datetime.datetime.fromtimestamp(int(value) // 1000)
|
|
|
ac7d03 |
+ return x509.format_datetime(value)
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
def validate_csr(ugettext, csr):
|
|
|
ac7d03 |
"""
|
|
|
ac7d03 |
Ensure the CSR is base64-encoded and can be decoded by our PKCS#10
|
|
|
ac7d03 |
@@ -1296,18 +1301,7 @@ class cert_find(Search, CertMethod):
|
|
|
ac7d03 |
|
|
|
ac7d03 |
return (DN(cert_obj.issuer), cert_obj.serial_number)
|
|
|
ac7d03 |
|
|
|
ac7d03 |
- def _get_cert_obj(self, cert, all, raw, pkey_only):
|
|
|
ac7d03 |
- obj = {'certificate': base64.b64encode(cert).decode('ascii')}
|
|
|
ac7d03 |
-
|
|
|
ac7d03 |
- full = not pkey_only and all
|
|
|
ac7d03 |
- if not raw:
|
|
|
ac7d03 |
- self.obj._parse(obj, full)
|
|
|
ac7d03 |
- if not full:
|
|
|
ac7d03 |
- del obj['certificate']
|
|
|
ac7d03 |
-
|
|
|
ac7d03 |
- return obj
|
|
|
ac7d03 |
-
|
|
|
ac7d03 |
- def _cert_search(self, all, raw, pkey_only, **options):
|
|
|
ac7d03 |
+ def _cert_search(self, pkey_only, **options):
|
|
|
ac7d03 |
result = collections.OrderedDict()
|
|
|
ac7d03 |
|
|
|
ac7d03 |
try:
|
|
|
ac7d03 |
@@ -1316,15 +1310,19 @@ class cert_find(Search, CertMethod):
|
|
|
ac7d03 |
return result, False, False
|
|
|
ac7d03 |
|
|
|
ac7d03 |
try:
|
|
|
ac7d03 |
- key = self._get_cert_key(cert)
|
|
|
ac7d03 |
+ issuer, serial_number = self._get_cert_key(cert)
|
|
|
ac7d03 |
except ValueError:
|
|
|
ac7d03 |
return result, True, True
|
|
|
ac7d03 |
|
|
|
ac7d03 |
- result[key] = self._get_cert_obj(cert, all, raw, pkey_only)
|
|
|
ac7d03 |
+ obj = {'serial_number': serial_number}
|
|
|
ac7d03 |
+ if not pkey_only:
|
|
|
ac7d03 |
+ obj['certificate'] = base64.b64encode(cert).decode('ascii')
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+ result[issuer, serial_number] = obj
|
|
|
ac7d03 |
|
|
|
ac7d03 |
return result, False, True
|
|
|
ac7d03 |
|
|
|
ac7d03 |
- def _ca_search(self, all, raw, pkey_only, exactly, **options):
|
|
|
ac7d03 |
+ def _ca_search(self, raw, pkey_only, exactly, **options):
|
|
|
ac7d03 |
ra_options = {}
|
|
|
ac7d03 |
for name in ('revocation_reason',
|
|
|
ac7d03 |
'issuer',
|
|
|
ac7d03 |
@@ -1357,7 +1355,6 @@ class cert_find(Search, CertMethod):
|
|
|
ac7d03 |
return result, False, complete
|
|
|
ac7d03 |
|
|
|
ac7d03 |
ca_objs = self.api.Command.ca_find(
|
|
|
ac7d03 |
- all=all,
|
|
|
ac7d03 |
timelimit=0,
|
|
|
ac7d03 |
sizelimit=0,
|
|
|
ac7d03 |
)['result']
|
|
|
ac7d03 |
@@ -1377,24 +1374,16 @@ class cert_find(Search, CertMethod):
|
|
|
ac7d03 |
obj = {'serial_number': serial_number}
|
|
|
ac7d03 |
else:
|
|
|
ac7d03 |
obj = ra_obj
|
|
|
ac7d03 |
- if all:
|
|
|
ac7d03 |
- obj.update(ra.get_certificate(str(serial_number)))
|
|
|
ac7d03 |
|
|
|
ac7d03 |
if not raw:
|
|
|
ac7d03 |
obj['issuer'] = issuer
|
|
|
ac7d03 |
obj['subject'] = DN(ra_obj['subject'])
|
|
|
ac7d03 |
+ obj['valid_not_before'] = (
|
|
|
ac7d03 |
+ convert_pkidatetime(obj['valid_not_before']))
|
|
|
ac7d03 |
+ obj['valid_not_after'] = (
|
|
|
ac7d03 |
+ convert_pkidatetime(obj['valid_not_after']))
|
|
|
ac7d03 |
obj['revoked'] = (
|
|
|
ac7d03 |
ra_obj['status'] in (u'REVOKED', u'REVOKED_EXPIRED'))
|
|
|
ac7d03 |
- if all:
|
|
|
ac7d03 |
- obj['certificate'] = (
|
|
|
ac7d03 |
- obj['certificate'].replace('\r\n', ''))
|
|
|
ac7d03 |
- self.obj._parse(obj)
|
|
|
ac7d03 |
-
|
|
|
ac7d03 |
- if 'certificate_chain' in ca_obj:
|
|
|
ac7d03 |
- cert = x509.load_certificate(obj['certificate'])
|
|
|
ac7d03 |
- cert_der = cert.public_bytes(serialization.Encoding.DER)
|
|
|
ac7d03 |
- obj['certificate_chain'] = (
|
|
|
ac7d03 |
- [cert_der] + ca_obj['certificate_chain'])
|
|
|
ac7d03 |
|
|
|
ac7d03 |
obj['cacn'] = ca_obj['cn'][0]
|
|
|
ac7d03 |
|
|
|
ac7d03 |
@@ -1402,7 +1391,7 @@ class cert_find(Search, CertMethod):
|
|
|
ac7d03 |
|
|
|
ac7d03 |
return result, False, complete
|
|
|
ac7d03 |
|
|
|
ac7d03 |
- def _ldap_search(self, all, raw, pkey_only, no_members, **options):
|
|
|
ac7d03 |
+ def _ldap_search(self, all, pkey_only, no_members, **options):
|
|
|
ac7d03 |
ldap = self.api.Backend.ldap2
|
|
|
ac7d03 |
|
|
|
ac7d03 |
filters = []
|
|
|
ac7d03 |
@@ -1461,26 +1450,25 @@ class cert_find(Search, CertMethod):
|
|
|
ac7d03 |
for attr in ('usercertificate', 'usercertificate;binary'):
|
|
|
ac7d03 |
for cert in entry.get(attr, []):
|
|
|
ac7d03 |
try:
|
|
|
ac7d03 |
- key = self._get_cert_key(cert)
|
|
|
ac7d03 |
+ issuer, serial_number = self._get_cert_key(cert)
|
|
|
ac7d03 |
except ValueError:
|
|
|
ac7d03 |
truncated = True
|
|
|
ac7d03 |
continue
|
|
|
ac7d03 |
|
|
|
ac7d03 |
try:
|
|
|
ac7d03 |
- obj = result[key]
|
|
|
ac7d03 |
+ obj = result[issuer, serial_number]
|
|
|
ac7d03 |
except KeyError:
|
|
|
ac7d03 |
- obj = self._get_cert_obj(cert, all, raw, pkey_only)
|
|
|
ac7d03 |
- result[key] = obj
|
|
|
ac7d03 |
+ obj = {'serial_number': serial_number}
|
|
|
ac7d03 |
+ if not pkey_only and all:
|
|
|
ac7d03 |
+ obj['certificate'] = (
|
|
|
ac7d03 |
+ base64.b64encode(cert).decode('ascii'))
|
|
|
ac7d03 |
+ result[issuer, serial_number] = obj
|
|
|
ac7d03 |
|
|
|
ac7d03 |
if not pkey_only and (all or not no_members):
|
|
|
ac7d03 |
owners = obj.setdefault('owner', [])
|
|
|
ac7d03 |
if entry.dn not in owners:
|
|
|
ac7d03 |
owners.append(entry.dn)
|
|
|
ac7d03 |
|
|
|
ac7d03 |
- if not raw:
|
|
|
ac7d03 |
- for obj in six.itervalues(result):
|
|
|
ac7d03 |
- self.obj._fill_owners(obj)
|
|
|
ac7d03 |
-
|
|
|
ac7d03 |
return result, truncated, complete
|
|
|
ac7d03 |
|
|
|
ac7d03 |
def execute(self, criteria=None, all=False, raw=False, pkey_only=False,
|
|
|
ac7d03 |
@@ -1537,6 +1525,37 @@ class cert_find(Search, CertMethod):
|
|
|
ac7d03 |
truncated = truncated or sub_truncated
|
|
|
ac7d03 |
complete = complete or sub_complete
|
|
|
ac7d03 |
|
|
|
ac7d03 |
+ if not pkey_only:
|
|
|
ac7d03 |
+ ca_objs = {}
|
|
|
ac7d03 |
+ ra = self.api.Backend.ra
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+ for key, obj in six.iteritems(result):
|
|
|
ac7d03 |
+ if all and 'cacn' in obj:
|
|
|
ac7d03 |
+ _issuer, serial_number = key
|
|
|
ac7d03 |
+ cacn = obj['cacn']
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+ try:
|
|
|
ac7d03 |
+ ca_obj = ca_objs[cacn]
|
|
|
ac7d03 |
+ except KeyError:
|
|
|
ac7d03 |
+ ca_obj = ca_objs[cacn] = (
|
|
|
ac7d03 |
+ self.api.Command.ca_show(cacn, all=True)['result'])
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+ obj.update(ra.get_certificate(str(serial_number)))
|
|
|
ac7d03 |
+ if not raw:
|
|
|
ac7d03 |
+ obj['certificate'] = (
|
|
|
ac7d03 |
+ obj['certificate'].replace('\r\n', ''))
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+ if 'certificate_chain' in ca_obj:
|
|
|
ac7d03 |
+ cert = x509.load_certificate(obj['certificate'])
|
|
|
ac7d03 |
+ cert_der = (
|
|
|
ac7d03 |
+ cert.public_bytes(serialization.Encoding.DER))
|
|
|
ac7d03 |
+ obj['certificate_chain'] = (
|
|
|
ac7d03 |
+ [cert_der] + ca_obj['certificate_chain'])
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+ if not raw:
|
|
|
ac7d03 |
+ self.obj._parse(obj, all)
|
|
|
ac7d03 |
+ self.obj._fill_owners(obj)
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
result = list(six.itervalues(result))
|
|
|
ac7d03 |
if sizelimit > 0 and len(result) > sizelimit:
|
|
|
ac7d03 |
if not truncated:
|
|
|
ac7d03 |
diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py
|
|
|
ac7d03 |
index d1dd707f145e0f58bfa721df55513d46c14358f2..3997531032746a22243a4219250af4172e9ae5b3 100644
|
|
|
ac7d03 |
--- a/ipaserver/plugins/dogtag.py
|
|
|
ac7d03 |
+++ b/ipaserver/plugins/dogtag.py
|
|
|
ac7d03 |
@@ -1945,6 +1945,16 @@ class ra(rabase.rabase, RestClient):
|
|
|
ac7d03 |
if len(issuer_dn) == 1:
|
|
|
ac7d03 |
response_request['issuer'] = unicode(issuer_dn[0].text)
|
|
|
ac7d03 |
|
|
|
ac7d03 |
+ not_valid_before = cert.xpath('NotValidBefore')
|
|
|
ac7d03 |
+ if len(not_valid_before) == 1:
|
|
|
ac7d03 |
+ response_request['valid_not_before'] = (
|
|
|
ac7d03 |
+ unicode(not_valid_before[0].text))
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+ not_valid_after = cert.xpath('NotValidAfter')
|
|
|
ac7d03 |
+ if len(not_valid_after) == 1:
|
|
|
ac7d03 |
+ response_request['valid_not_after'] = (
|
|
|
ac7d03 |
+ unicode(not_valid_after[0].text))
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
status = cert.xpath('Status')
|
|
|
ac7d03 |
if len(status) == 1:
|
|
|
ac7d03 |
response_request['status'] = unicode(status[0].text)
|
|
|
ac7d03 |
--
|
|
|
ac7d03 |
2.12.2
|
|
|
ac7d03 |
|