summaryrefslogtreecommitdiffstats
path: root/ipaserver/plugins
diff options
context:
space:
mode:
authorFraser Tweedale <ftweedal@redhat.com>2016-08-08 14:27:20 +1000
committerJan Cholasta <jcholast@redhat.com>2016-12-12 13:03:15 +0100
commit32b1743e5fb318b226a602ec8d9a4b6ef2a25c9d (patch)
tree484f57785d6f872f22e118aed13df38d74a2591e /ipaserver/plugins
parentcc5b88e5d4ac1171374be9ae8e6e60730243dd3d (diff)
downloadfreeipa-32b1743e5fb318b226a602ec8d9a4b6ef2a25c9d.tar.gz
freeipa-32b1743e5fb318b226a602ec8d9a4b6ef2a25c9d.tar.xz
freeipa-32b1743e5fb318b226a602ec8d9a4b6ef2a25c9d.zip
Add options to write lightweight CA cert or chain to file
Administrators need a way to retrieve the certificate or certificate chain of an IPA-managed lightweight CA. Add params to the `ca' object for carrying the CA certificate and chain (as multiple DER values). Add the `--chain' flag for including the chain in the result (chain is also included with `--all'). Add the `--certificate-out' option for writing the certificate to a file (or the chain, if `--chain' was given). Fixes: https://fedorahosted.org/freeipa/ticket/6178 Reviewed-By: Jan Cholasta <jcholast@redhat.com> Reviewed-By: Tomas Krizek <tkrizek@redhat.com>
Diffstat (limited to 'ipaserver/plugins')
-rw-r--r--ipaserver/plugins/ca.py65
-rw-r--r--ipaserver/plugins/dogtag.py12
2 files changed, 72 insertions, 5 deletions
diff --git a/ipaserver/plugins/ca.py b/ipaserver/plugins/ca.py
index d9ae8c81f..ef1d68c3a 100644
--- a/ipaserver/plugins/ca.py
+++ b/ipaserver/plugins/ca.py
@@ -2,14 +2,18 @@
# Copyright (C) 2016 FreeIPA Contributors see COPYING for license
#
-from ipalib import api, errors, output, DNParam, Str
+import base64
+
+import six
+
+from ipalib import api, errors, output, Bytes, DNParam, Flag, Str
from ipalib.constants import IPA_CA_CN
from ipalib.plugable import Registry
from ipaserver.plugins.baseldap import (
LDAPObject, LDAPSearch, LDAPCreate, LDAPDelete,
LDAPUpdate, LDAPRetrieve, LDAPQuery, pkey_to_value)
from ipaserver.plugins.cert import ca_enabled_check
-from ipalib import _, ngettext
+from ipalib import _, ngettext, x509
__doc__ = _("""
@@ -100,6 +104,18 @@ class ca(LDAPObject):
doc=_('Issuer Distinguished Name'),
flags=['no_create', 'no_update'],
),
+ Bytes(
+ 'certificate',
+ label=_("Certificate"),
+ doc=_("Base-64 encoded certificate."),
+ flags={'no_create', 'no_update', 'no_search'},
+ ),
+ Bytes(
+ 'certificate_chain*',
+ label=_("Certificate chain"),
+ doc=_("X.509 certificate chain"),
+ flags={'no_create', 'no_update', 'no_search'},
+ ),
)
permission_filter_objectclasses = ['ipaca']
@@ -145,6 +161,21 @@ class ca(LDAPObject):
}
+def set_certificate_attrs(entry, options, always_include_cert=True):
+ ca_id = entry['ipacaid'][0]
+ full = options.get('all', False)
+ with api.Backend.ra_lightweight_ca as ca_api:
+ if always_include_cert or full:
+ der = ca_api.read_ca_cert(ca_id)
+ entry['certificate'] = six.text_type(base64.b64encode(der))
+
+ if options.get('chain', False) or full:
+ pkcs7_der = ca_api.read_ca_chain(ca_id)
+ pems = x509.pkcs7_to_pems(pkcs7_der, x509.DER)
+ ders = [x509.normalize_certificate(pem) for pem in pems]
+ entry['certificate_chain'] = ders
+
+
@register()
class ca_find(LDAPSearch):
__doc__ = _("Search for CAs.")
@@ -154,16 +185,32 @@ class ca_find(LDAPSearch):
def execute(self, *keys, **options):
ca_enabled_check()
- return super(ca_find, self).execute(*keys, **options)
+ result = super(ca_find, self).execute(*keys, **options)
+ for entry in result['result']:
+ set_certificate_attrs(entry, options, always_include_cert=False)
+ return result
+
+
+_chain_flag = Flag(
+ 'chain',
+ default=False,
+ doc=_('Include certificate chain in output'),
+)
@register()
class ca_show(LDAPRetrieve):
__doc__ = _("Display the properties of a CA.")
- def execute(self, *args, **kwargs):
+ takes_options = LDAPRetrieve.takes_options + (
+ _chain_flag,
+ )
+
+ def execute(self, *keys, **options):
ca_enabled_check()
- return super(ca_show, self).execute(*args, **kwargs)
+ result = super(ca_show, self).execute(*keys, **options)
+ set_certificate_attrs(result['result'], options)
+ return result
@register()
@@ -171,6 +218,10 @@ class ca_add(LDAPCreate):
__doc__ = _("Create a CA.")
msg_summary = _('Created CA "%(value)s"')
+ takes_options = LDAPCreate.takes_options + (
+ _chain_flag,
+ )
+
def pre_callback(self, ldap, dn, entry, entry_attrs, *keys, **options):
ca_enabled_check()
if not ldap.can_add(dn[1:]):
@@ -203,6 +254,10 @@ class ca_add(LDAPCreate):
entry['ipacasubjectdn'] = [resp['dn']]
return dn
+ def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ set_certificate_attrs(entry_attrs, options)
+ return dn
+
@register()
class ca_del(LDAPDelete):
diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py
index 0bdb4daf2..b77b21aa2 100644
--- a/ipaserver/plugins/dogtag.py
+++ b/ipaserver/plugins/dogtag.py
@@ -2125,6 +2125,18 @@ class ra_lightweight_ca(RestClient):
except:
raise errors.RemoteRetrieveError(reason=_("Response from CA was not valid JSON"))
+ def read_ca_cert(self, ca_id):
+ _status, _resp_headers, resp_body = self._ssldo(
+ 'GET', '{}/cert'.format(ca_id),
+ headers={'Accept': 'application/pkix-cert'})
+ return resp_body
+
+ def read_ca_chain(self, ca_id):
+ _status, _resp_headers, resp_body = self._ssldo(
+ 'GET', '{}/chain'.format(ca_id),
+ headers={'Accept': 'application/pkcs7-mime'})
+ return resp_body
+
def disable_ca(self, ca_id):
self._ssldo(
'POST', ca_id + '/disable',