URL: https://github.com/freeipa/freeipa/pull/2630
Author: flo-renaud
 Title: #2630: PKINIT: fix ipa-pkinit-manage enable|disable
Action: opened

PR body:
"""
## PKINIT: fix ipa-pkinit-manage enable|disable

The command ipa-pkinit-manage enable|disable is reporting success even though 
the PKINIT cert is not re-issued.
The command triggers the request of a new certificate (signed by IPA CA when 
state=enable, selfsigned when disabled), but as the cert file is still present, 
certmonger does not create a new request and the existing certificate is kept.
The fix consists in deleting the cert and key file before calling certmonger to 
request a new cert.

There was also an issue in the is_pkinit_enabled() function: if no tracking 
request was found for the PKINIT cert, is_pkinit_enabled() was returning True 
while it should not.

Fixes https://pagure.io/freeipa/issue/7200

## ipatest: add test for ipa-pkinit-manage enable|disable
Add a test for ipa-pkinit-manage with the following scenario:
- install master with option --no-pkinit
- call ipa-pkinit-manage enable
- call ipa-pkinit-manage disable
- call ipa-pkinit-manage enable
    
At each step, check that the PKINIT cert is consistent with the expectations: 
when pkinit is enabled, the cert is signed by IPA CA and tracked by 'IPA' ca 
helper, but when pkinit is disabled, the cert is self-signed and tracked by 
'SelfSign' CA helper.

Related to https://pagure.io/freeipa/issue/7200

"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/2630/head:pr2630
git checkout pr2630
From f666aeee4853d74db67065ca92a5a19534fada38 Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <f...@redhat.com>
Date: Fri, 30 Nov 2018 15:46:25 +0100
Subject: [PATCH 1/2] ipatest: add test for ipa-pkinit-manage enable|disable

Add a test for ipa-pkinit-manage with the following scenario:
- install master with option --no-pkinit
- call ipa-pkinit-manage enable
- call ipa-pkinit-manage disable
- call ipa-pkinit-manage enable

At each step, check that the PKINIT cert is consistent with the
expectations: when pkinit is enabled, the cert is signed by IPA
CA and tracked by 'IPA' ca helper, but when pkinit is disabled,
the cert is self-signed and tracked by 'SelfSign' CA helper.

Related to https://pagure.io/freeipa/issue/7200
---
 .../test_integration/test_pkinit_manage.py    | 111 ++++++++++++++++++
 1 file changed, 111 insertions(+)
 create mode 100644 ipatests/test_integration/test_pkinit_manage.py

diff --git a/ipatests/test_integration/test_pkinit_manage.py b/ipatests/test_integration/test_pkinit_manage.py
new file mode 100644
index 0000000000..bc1d9e338c
--- /dev/null
+++ b/ipatests/test_integration/test_pkinit_manage.py
@@ -0,0 +1,111 @@
+#
+# Copyright (C) 2018  FreeIPA Contributors see COPYING for license
+#
+
+"""
+Module provides tests for the ipa-pkinit-manage command.
+"""
+
+from __future__ import absolute_import
+
+from ipalib import x509
+from ipaplatform.paths import paths
+from ipapython.dn import DN
+from ipatests.test_integration.base import IntegrationTest
+from ipatests.pytest_ipa.integration import tasks
+
+
+SELFSIGNED_CA_HELPER = 'SelfSign'
+IPA_CA_HELPER = 'IPA'
+PKINIT_STATUS_ENABLED = 'enabled'
+PKINIT_STATUS_DISABLED = 'disabled'
+
+
+def check_pkinit_status(host, status):
+    """Ensures that ipa-pkinit-manage status returns the expected state"""
+    result = host.run_command(['ipa-pkinit-manage', 'status'],
+                              raiseonerr=False)
+    assert result.returncode == 0
+    assert 'PKINIT is {}'.format(status) in result.stdout_text
+
+
+def check_pkinit_tracking(host, ca_helper):
+    """Ensures that the PKINIT cert is tracked by the expected helper"""
+    result = host.run_command(['getcert', 'list', '-f', paths.KDC_CERT],
+                              raiseonerr=False)
+    assert result.returncode == 0
+    # Make sure that only one request exists
+    assert result.stdout_text.count('Request ID') == 1
+    # Make sure that the right CA helper is used to track the cert
+    assert 'CA: {}'.format(ca_helper) in result.stdout_text
+
+
+def check_pkinit_cert_issuer(host, issuer):
+    """Ensures that the PKINIT cert is signed by the expected issuer"""
+    data = host.get_file_contents(paths.KDC_CERT)
+    pkinit_cert = x509.load_pem_x509_certificate(data)
+    # Make sure that the issuer is the expected one
+    assert DN(pkinit_cert.issuer) == DN(issuer)
+
+
+def check_pkinit(host, enabled=True):
+    """Checks that PKINIT is configured as expected
+
+    If enabled:
+    ipa-pkinit-manage status must return 'PKINIT is enabled'
+    the certificate must be tracked by IPA CA helper
+    the certificate must be signed by IPA CA
+    If disabled:
+    ipa-pkinit-manage status must return 'PKINIT is disabled'
+    the certificate must be tracked by SelfSign CA helper
+    the certificate must be self-signed
+    """
+    if enabled:
+        # When pkinit is enabled:
+        # cert is tracked by IPA CA helper
+        # cert is signed by IPA CA
+        check_pkinit_status(host, PKINIT_STATUS_ENABLED)
+        check_pkinit_tracking(host, IPA_CA_HELPER)
+        check_pkinit_cert_issuer(
+            host,
+            'CN=Certificate Authority,O={}'.format(host.domain.realm))
+    else:
+        # When pkinit is disabled
+        # cert is tracked by 'SelfSign' CA helper
+        # cert is self-signed
+        check_pkinit_status(host, PKINIT_STATUS_DISABLED)
+        check_pkinit_tracking(host, SELFSIGNED_CA_HELPER)
+        check_pkinit_cert_issuer(
+            host,
+            'CN={},O={}'.format(host.hostname, host.domain.realm))
+
+
+class TestPkinitManage(IntegrationTest):
+    """Tests the ipa-pkinit-manage command.
+
+    ipa-pkinit-manage can be used to enable, disable or check
+    the status of PKINIT.
+    When pkinit is enabled, the kerberos server is using a certificate
+    signed either externally or by IPA CA. In the latter case, certmonger
+    is tracking the cert with IPA helper.
+    When pkinit is disabled, the kerberos server is using a self-signed
+    certificate that is tracked by certmonger with the SelfSigned helper.
+    """
+
+    @classmethod
+    def install(cls, mh):
+        # Install the master with PKINIT disabled
+        tasks.install_master(cls.master, extra_args=['--no-pkinit'])
+        check_pkinit(cls.master, enabled=False)
+
+    def test_pkinit_enable(self):
+        self.master.run_command(['ipa-pkinit-manage', 'enable'])
+        check_pkinit(self.master, enabled=True)
+
+    def test_pkinit_disable(self):
+        self.master.run_command(['ipa-pkinit-manage', 'disable'])
+        check_pkinit(self.master, enabled=False)
+
+    def test_pkinit_reenable(self):
+        self.master.run_command(['ipa-pkinit-manage', 'enable'])
+        check_pkinit(self.master, enabled=True)

From a5ecc455bf67b49632c54ec983184b4e4c1037e6 Mon Sep 17 00:00:00 2001
From: Florence Blanc-Renaud <f...@redhat.com>
Date: Fri, 30 Nov 2018 15:49:20 +0100
Subject: [PATCH 2/2] PKINIT: fix ipa-pkinit-manage enable|disable

The command ipa-pkinit-manage enable|disable is reporting
success even though the PKINIT cert is not re-issued.
The command triggers the request of a new certificate
(signed by IPA CA when state=enable, selfsigned when disabled),
but as the cert file is still present, certmonger does not create
a new request and the existing certificate is kept.

The fix consists in deleting the cert and key file before calling
certmonger to request a new cert.

There was also an issue in the is_pkinit_enabled() function:
if no tracking request was found for the PKINIT cert,
is_pkinit_enabled() was returning True while it should not.

Fixes https://pagure.io/freeipa/issue/7200
---
 ipaserver/install/ipa_pkinit_manage.py | 2 ++
 ipaserver/install/krbinstance.py       | 9 ++++++---
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/ipaserver/install/ipa_pkinit_manage.py b/ipaserver/install/ipa_pkinit_manage.py
index 4a79bba5d1..86bd1baf00 100644
--- a/ipaserver/install/ipa_pkinit_manage.py
+++ b/ipaserver/install/ipa_pkinit_manage.py
@@ -72,6 +72,8 @@ def _setup(self, setup_pkinit):
                 if ca_enabled:
                     logger.warning(
                         "Failed to stop tracking certificates: %s", e)
+            # remove the cert and key
+            krb.delete_pkinit_cert()
 
             krb.enable_ssl()
 
diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py
index 4ead1c55f1..850946afb4 100644
--- a/ipaserver/install/krbinstance.py
+++ b/ipaserver/install/krbinstance.py
@@ -77,7 +77,7 @@ def is_pkinit_enabled():
     if os.path.exists(paths.KDC_CERT):
         pkinit_request_ca = get_pkinit_request_ca()
 
-        if pkinit_request_ca != "SelfSign":
+        if pkinit_request_ca and pkinit_request_ca != "SelfSign":
             return True
 
     return False
@@ -602,6 +602,10 @@ def __convert_to_gssapi_replication(self):
     def stop_tracking_certs(self):
         certmonger.stop_tracking(certfile=paths.KDC_CERT)
 
+    def delete_pkinit_cert(self):
+        installutils.remove_file(paths.KDC_CERT)
+        installutils.remove_file(paths.KDC_KEY)
+
     def uninstall(self):
         if self.is_configured():
             self.print_msg("Unconfiguring %s" % self.service_name)
@@ -627,8 +631,7 @@ def uninstall(self):
         # stop tracking and remove certificates
         self.stop_tracking_certs()
         installutils.remove_file(paths.CACERT_PEM)
-        installutils.remove_file(paths.KDC_CERT)
-        installutils.remove_file(paths.KDC_KEY)
+        self.delete_pkinit_cert()
 
         if running:
             self.restart()
_______________________________________________
FreeIPA-devel mailing list -- freeipa-devel@lists.fedorahosted.org
To unsubscribe send an email to freeipa-devel-le...@lists.fedorahosted.org
Fedora Code of Conduct: https://getfedora.org/code-of-conduct.html
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedorahosted.org/archives/list/freeipa-devel@lists.fedorahosted.org

Reply via email to