Please review the attached patch with adds --certificate-out and --certificate-chain-out options to `ca-show' command.
Note that --certificate-chain-out currently writes a bogus file due to a bug in Dogtag that will be fixed in this week's build. https://fedorahosted.org/freeipa/ticket/6178 Thanks, Fraser
From 6d3a153a954ab09022af6073ae9ea68668716618 Mon Sep 17 00:00:00 2001 From: Fraser Tweedale <ftwee...@redhat.com> Date: Mon, 8 Aug 2016 14:27:20 +1000 Subject: [PATCH] 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 --certificate-out and --certificate-chain-out options to the `ca-show` command. Fixes: https://fedorahosted.org/freeipa/ticket/6178 --- API.txt | 4 +++- VERSION | 4 ++-- ipaclient/plugins/ca.py | 40 ++++++++++++++++++++++++++++++++++++++++ ipaserver/plugins/ca.py | 23 +++++++++++++++++++++-- ipaserver/plugins/dogtag.py | 12 ++++++++++++ 5 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 ipaclient/plugins/ca.py diff --git a/API.txt b/API.txt index 535d8ec9a4990395207e2455a09a8c1bdef5529a..6ed8c5348876aa6ce1ab5d11e14dbcb1e7cee768 100644 --- a/API.txt +++ b/API.txt @@ -505,9 +505,11 @@ output: Entry('result') output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>]) output: PrimaryKey('value') command: ca_show/1 -args: 1,4,3 +args: 1,6,3 arg: Str('cn', cli_name='name') option: Flag('all', autofill=True, cli_name='all', default=False) +option: Str('certificate_chain_out?') +option: Str('certificate_out?') option: Flag('raw', autofill=True, cli_name='raw', default=False) option: Flag('rights', autofill=True, default=False) option: Str('version?') diff --git a/VERSION b/VERSION index ca489965050f32d2d8987dfd251ec2b2a0ba1768..3cdb27b806013be2cb0b8b2132c99302865e6358 100644 --- a/VERSION +++ b/VERSION @@ -90,5 +90,5 @@ IPA_DATA_VERSION=20100614120000 # # ######################################################## IPA_API_VERSION_MAJOR=2 -IPA_API_VERSION_MINOR=211 -# Last change: mbabinsk: allow 'value' output param in commands without primary key +IPA_API_VERSION_MINOR=212 +# Last change: ftweedal: ca: add options to write cert or cert chain to file diff --git a/ipaclient/plugins/ca.py b/ipaclient/plugins/ca.py new file mode 100644 index 0000000000000000000000000000000000000000..1f4a7c6074b5eb139e01ba2963bf46399ce6d645 --- /dev/null +++ b/ipaclient/plugins/ca.py @@ -0,0 +1,40 @@ +# +# Copyright (C) 2016 FreeIPA Contributors see COPYING for license +# + +from ipaclient.frontend import MethodOverride +from ipalib import util +from ipalib.plugable import Registry +from ipalib.text import _ + +register = Registry() + + +@register(override=True, no_fail=True) +class ca_show(MethodOverride): + def forward(self, *keys, **options): + if 'certificate_out' in options: + util.check_writable_file(options['certificate_out']) + if 'certificate_chain_out' in options: + util.check_writable_file(options['certificate_chain_out']) + + result = super(ca_show, self).forward(*keys, **options) + summaries = [] + if 'certificate_out' in options and 'certificate' in result['result']: + with open(options['certificate_out'], 'wb') as f: + f.write(result['result'].pop('certificate')) + summaries.append ( + _("Certificate written to file '%(file)s'") + % dict(file=options['certificate_out']) + ) + if 'certificate_chain_out' in options and 'chain' in result['result']: + with open(options['certificate_chain_out'], 'wb') as f: + f.write(result['result'].pop('chain')) + summaries.append ( + _("Certificate chain written to file '%(file)s'") + % dict(file=options['certificate_chain_out']) + ) + if len(summaries) > 0: + result['summary'] = '\n'.join(summaries) + + return result diff --git a/ipaserver/plugins/ca.py b/ipaserver/plugins/ca.py index 966ae2b1bdb4bb0207dfa58f0e9c951bc930f766..70aaca19dbece452c8e679a58ce3754ea75666c5 100644 --- a/ipaserver/plugins/ca.py +++ b/ipaserver/plugins/ca.py @@ -140,9 +140,28 @@ class ca_find(LDAPSearch): class ca_show(LDAPRetrieve): __doc__ = _("Display the properties of a CA.") - def execute(self, *args, **kwargs): + takes_options = LDAPRetrieve.takes_options + ( + Str('certificate_out?', + doc=_('Write certificate to file'), + ), + Str('certificate_chain_out?', + doc=_('Write PKCS #7 certificate chain to file'), + ), + ) + + def execute(self, *keys, **options): ca_enabled_check() - return super(ca_show, self).execute(*args, **kwargs) + result = super(ca_show, self).execute(*keys, **options) + + ca_id = result['result']['ipacaid'][0] + if 'certificate_out' in options: + with self.api.Backend.ra_lightweight_ca as ca_api: + result['result']['certificate'] = ca_api.read_ca_cert(ca_id) + if 'certificate_chain_out' in options: + with self.api.Backend.ra_lightweight_ca as ca_api: + result['result']['chain'] = ca_api.read_ca_chain(ca_id) + + return result @register() diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py index aef1e888eb1b6c273c1fd12cbf4912407f8f8132..ea78f4ee93d3bd16a2088cf82618e72a9dcf9268 100644 --- a/ipaserver/plugins/dogtag.py +++ b/ipaserver/plugins/dogtag.py @@ -2205,6 +2205,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/x-pem-file'}) + 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/x-pem-file'}) + return resp_body + def disable_ca(self, ca_id): self._ssldo( 'POST', ca_id + '/disable', -- 2.5.5
-- Manage your subscription for the Freeipa-devel mailing list: https://www.redhat.com/mailman/listinfo/freeipa-devel Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code