summaryrefslogtreecommitdiffstats
path: root/ipaclient/plugins
diff options
context:
space:
mode:
authorBen Lipton <blipton@redhat.com>2016-08-22 10:46:02 -0400
committerJan Cholasta <jcholast@redhat.com>2017-02-28 09:02:49 +0000
commit39a5d9c5aae77687f67d9be02457733bdfb99ead (patch)
tree154db132be60de39643b31ad0efa23aca33521dd /ipaclient/plugins
parent16dac0252e52c8de07fd8a6a86ec0896074cbe9d (diff)
downloadfreeipa-39a5d9c5aae77687f67d9be02457733bdfb99ead.tar.gz
freeipa-39a5d9c5aae77687f67d9be02457733bdfb99ead.tar.xz
freeipa-39a5d9c5aae77687f67d9be02457733bdfb99ead.zip
csrgen: Automate full cert request flow
Allows the `ipa cert-request` command to generate its own CSR. It no longer requires a CSR passed on the command line, instead it creates a config (bash script) with `cert-get-requestdata`, then runs it to build a CSR, and submits that CSR. Example usage (NSS database): $ ipa cert-request --principal host/test.example.com --profile-id caIPAserviceCert --database /tmp/certs Example usage (PEM private key file): $ ipa cert-request --principal host/test.example.com --profile-id caIPAserviceCert --private-key /tmp/key.pem https://fedorahosted.org/freeipa/ticket/4899 Reviewed-By: Jan Cholasta <jcholast@redhat.com>
Diffstat (limited to 'ipaclient/plugins')
-rw-r--r--ipaclient/plugins/cert.py76
-rw-r--r--ipaclient/plugins/csrgen.py5
2 files changed, 79 insertions, 2 deletions
diff --git a/ipaclient/plugins/cert.py b/ipaclient/plugins/cert.py
index 1075972c4..5d712b516 100644
--- a/ipaclient/plugins/cert.py
+++ b/ipaclient/plugins/cert.py
@@ -19,6 +19,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import subprocess
+from tempfile import NamedTemporaryFile as NTF
+
+import six
+
from ipaclient.frontend import MethodOverride
from ipalib import errors
from ipalib import x509
@@ -27,17 +32,86 @@ from ipalib.parameters import File, Flag, Str
from ipalib.plugable import Registry
from ipalib.text import _
+if six.PY3:
+ unicode = str
+
register = Registry()
@register(override=True, no_fail=True)
class cert_request(MethodOverride):
+ takes_options = (
+ Str(
+ 'database?',
+ label=_('Path to NSS database'),
+ doc=_('Path to NSS database to use for private key'),
+ ),
+ Str(
+ 'private_key?',
+ label=_('Path to private key file'),
+ doc=_('Path to PEM file containing a private key'),
+ ),
+ )
+
def get_args(self):
for arg in super(cert_request, self).get_args():
if arg.name == 'csr':
- arg = arg.clone_retype(arg.name, File)
+ arg = arg.clone_retype(arg.name, File, required=False)
yield arg
+ def forward(self, csr=None, **options):
+ database = options.pop('database', None)
+ private_key = options.pop('private_key', None)
+
+ if csr is None:
+ if database:
+ helper = u'certutil'
+ helper_args = ['-d', database]
+ elif private_key:
+ helper = u'openssl'
+ helper_args = [private_key]
+ else:
+ raise errors.InvocationError(
+ message=u"One of 'database' or 'private_key' is required")
+
+ with NTF() as scriptfile, NTF() as csrfile:
+ profile_id = options.get('profile_id')
+
+ self.api.Command.cert_get_requestdata(
+ profile_id=profile_id,
+ principal=options.get('principal'),
+ out=unicode(scriptfile.name),
+ helper=helper)
+
+ helper_cmd = [
+ 'bash', '-e', scriptfile.name, csrfile.name] + helper_args
+
+ try:
+ subprocess.check_output(helper_cmd)
+ except subprocess.CalledProcessError as e:
+ raise errors.CertificateOperationError(
+ error=(
+ _('Error running "%(cmd)s" to generate CSR:'
+ ' %(err)s') %
+ {'cmd': ' '.join(helper_cmd), 'err': e.output}))
+
+ try:
+ csr = unicode(csrfile.read())
+ except IOError as e:
+ raise errors.CertificateOperationError(
+ error=(_('Unable to read generated CSR file: %(err)s')
+ % {'err': e}))
+ if not csr:
+ raise errors.CertificateOperationError(
+ error=(_('Generated CSR was empty')))
+ else:
+ if database is not None or private_key is not None:
+ raise errors.MutuallyExclusiveError(reason=_(
+ "Options 'database' and 'private_key' are not compatible"
+ " with 'csr'"))
+
+ return super(cert_request, self).forward(csr, **options)
+
@register(override=True, no_fail=True)
class cert_show(MethodOverride):
diff --git a/ipaclient/plugins/csrgen.py b/ipaclient/plugins/csrgen.py
index 0669a4775..0d6eca0cf 100644
--- a/ipaclient/plugins/csrgen.py
+++ b/ipaclient/plugins/csrgen.py
@@ -13,6 +13,7 @@ from ipalib.frontend import Local, Str
from ipalib.parameters import Principal
from ipalib.plugable import Registry
from ipalib.text import _
+from ipapython import dogtag
if six.PY3:
unicode = str
@@ -36,7 +37,7 @@ class cert_get_requestdata(Local):
' HTTP/test.example.com)'),
),
Str(
- 'profile_id',
+ 'profile_id?',
label=_('Profile ID'),
doc=_('CSR Generation Profile to use'),
),
@@ -73,6 +74,8 @@ class cert_get_requestdata(Local):
principal = options.get('principal')
profile_id = options.get('profile_id')
+ if profile_id is None:
+ profile_id = dogtag.DEFAULT_PROFILE
helper = options.get('helper')
if self.api.env.in_server: