7e1b55
From a620e5e9e152defe144705913521c3cf556faa0e Mon Sep 17 00:00:00 2001
7e1b55
From: Mohammad Rizwan <myusuf@redhat.com>
7e1b55
Date: Mon, 26 Apr 2021 15:50:20 +0530
7e1b55
Subject: [PATCH] ipatests: wait while http/ldap/pkinit cert get renew on
7e1b55
 replica
7e1b55
7e1b55
LDAP/HTTP/PKINIT certificates should be renewd on replica after
7e1b55
moving system date. Test was failing because ipa-cert-fix ran
7e1b55
while these cert was not renewd and it tried to fix it.
7e1b55
7e1b55
This test adds check for replication before calling ipa-cert-fix
7e1b55
on replica.
7e1b55
7e1b55
Fixes: https://pagure.io/freeipa/issue/8815
7e1b55
7e1b55
Signed-off-by: Mohammad Rizwan <myusuf@redhat.com>
7e1b55
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
7e1b55
Reviewed-By: Sergey Orlov <sorlov@redhat.com>
7e1b55
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
7e1b55
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
7e1b55
---
7e1b55
 .../test_integration/test_ipa_cert_fix.py     | 172 +++++++++++++++---
7e1b55
 1 file changed, 144 insertions(+), 28 deletions(-)
7e1b55
7e1b55
diff --git a/ipatests/test_integration/test_ipa_cert_fix.py b/ipatests/test_integration/test_ipa_cert_fix.py
7e1b55
index a20996737..fa69743e2 100644
7e1b55
--- a/ipatests/test_integration/test_ipa_cert_fix.py
7e1b55
+++ b/ipatests/test_integration/test_ipa_cert_fix.py
7e1b55
@@ -5,16 +5,19 @@
7e1b55
 """
7e1b55
 Module provides tests for ipa-cert-fix CLI.
7e1b55
 """
7e1b55
+from cryptography.hazmat.backends import default_backend
7e1b55
+from cryptography import x509
7e1b55
+from datetime import datetime, date
7e1b55
 import pytest
7e1b55
-import re
7e1b55
 import time
7e1b55
 
7e1b55
 import logging
7e1b55
 from ipaplatform.paths import paths
7e1b55
+from ipapython.ipaldap import realm_to_serverid
7e1b55
 from ipatests.pytest_ipa.integration import tasks
7e1b55
 from ipatests.test_integration.base import IntegrationTest
7e1b55
 from ipatests.test_integration.test_caless import CALessBase, ipa_certs_cleanup
7e1b55
-
7e1b55
+from ipatests.test_integration.test_cert import get_certmonger_fs_id
7e1b55
 
7e1b55
 logger = logging.getLogger(__name__)
7e1b55
 
7e1b55
@@ -59,6 +62,49 @@ def move_date(host, chrony_state, date_str):
7e1b55
     host.run_command(['date', '-s', date_str])
7e1b55
 
7e1b55
 
7e1b55
+def needs_resubmit(host, req_id):
7e1b55
+    """Helper method to identify if cert request needs to be resubmitted
7e1b55
+    :param host: the host
7e1b55
+    :param req_id: request id to perform operation for
7e1b55
+
7e1b55
+    Returns True if resubmit needed else False
7e1b55
+    """
7e1b55
+    # check if cert is in monitoring state
7e1b55
+    tasks.wait_for_certmonger_status(
7e1b55
+        host, ('MONITORING'), req_id, timeout=600
7e1b55
+    )
7e1b55
+
7e1b55
+    # check if cert is valid and not expired
7e1b55
+    cmd = host.run_command(
7e1b55
+        'getcert list -i {} | grep expires'.format(req_id)
7e1b55
+    )
7e1b55
+    cert_expiry = cmd.stdout_text.split(' ')
7e1b55
+    cert_expiry = datetime.strptime(cert_expiry[1], '%Y-%m-%d').date()
7e1b55
+    if cert_expiry > date.today():
7e1b55
+        return False
7e1b55
+    else:
7e1b55
+        return True
7e1b55
+
7e1b55
+
7e1b55
+def get_cert_expiry(host, nssdb_path, cert_nick):
7e1b55
+    """Method to get cert expiry date of given certificate
7e1b55
+
7e1b55
+    :param host: the host
7e1b55
+    :param nssdb_path: nssdb path of certificate
7e1b55
+    :param cert_nick: certificate nick name for extracting cert from nssdb
7e1b55
+    """
7e1b55
+    # get initial expiry date to compare later with renewed cert
7e1b55
+    host.run_command([
7e1b55
+        'certutil', '-L', '-a',
7e1b55
+        '-d', nssdb_path,
7e1b55
+        '-n', cert_nick,
7e1b55
+        '-o', '/root/cert.pem'
7e1b55
+    ])
7e1b55
+    data = host.get_file_contents('/root/cert.pem')
7e1b55
+    cert = x509.load_pem_x509_certificate(data, backend=default_backend())
7e1b55
+    return cert.not_valid_after
7e1b55
+
7e1b55
+
7e1b55
 @pytest.fixture
7e1b55
 def expire_cert_critical():
7e1b55
     """
7e1b55
@@ -353,7 +399,19 @@ class TestCertFixReplica(IntegrationTest):
7e1b55
             setup_dns=False, extra_args=['--no-ntp']
7e1b55
         )
7e1b55
 
7e1b55
-    def test_renew_expired_cert_replica(self):
7e1b55
+    @pytest.fixture
7e1b55
+    def expire_certs(self):
7e1b55
+        # move system date to expire certs
7e1b55
+        for host in self.master, self.replicas[0]:
7e1b55
+            tasks.move_date(host, 'stop', '+3years+1days')
7e1b55
+
7e1b55
+        yield
7e1b55
+
7e1b55
+        # move date back on replica and master
7e1b55
+        for host in self.master, self.replicas[0]:
7e1b55
+            tasks.move_date(host, 'start', '-3years-1days')
7e1b55
+
7e1b55
+    def test_renew_expired_cert_replica(self, expire_certs):
7e1b55
         """Test renewal of certificates on replica with ipa-cert-fix
7e1b55
 
7e1b55
         This is to check that ipa-cert-fix renews the certificates
7e1b55
@@ -361,8 +419,6 @@ class TestCertFixReplica(IntegrationTest):
7e1b55
 
7e1b55
         related: https://pagure.io/freeipa/issue/7885
7e1b55
         """
7e1b55
-        move_date(self.master, 'stop', '+3years+1days')
7e1b55
-
7e1b55
         # wait for cert expiry
7e1b55
         check_status(self.master, 8, "CA_UNREACHABLE")
7e1b55
 
7e1b55
@@ -370,35 +426,95 @@ class TestCertFixReplica(IntegrationTest):
7e1b55
 
7e1b55
         check_status(self.master, 9, "MONITORING")
7e1b55
 
7e1b55
-        # move system date to expire cert on replica
7e1b55
-        move_date(self.replicas[0], 'stop', '+3years+1days')
7e1b55
-
7e1b55
-        # RA agent cert will be expired and in CA_UNREACHABLE state
7e1b55
-        check_status(self.replicas[0], 1, "CA_UNREACHABLE")
7e1b55
-
7e1b55
-        # renew RA agent cert
7e1b55
-        self.replicas[0].run_command(
7e1b55
-            ['ipa-cert-fix', '-v'], stdin_text='yes\n'
7e1b55
+        # replica operations
7e1b55
+        # 'Server-Cert cert-pki-ca' cert will be in CA_UNREACHABLE state
7e1b55
+        cmd = self.replicas[0].run_command(
7e1b55
+            ['getcert', 'list',
7e1b55
+             '-d', paths.PKI_TOMCAT_ALIAS_DIR,
7e1b55
+             '-n', 'Server-Cert cert-pki-ca']
7e1b55
+        )
7e1b55
+        req_id = get_certmonger_fs_id(cmd.stdout_text)
7e1b55
+        tasks.wait_for_certmonger_status(
7e1b55
+            self.replicas[0], ('CA_UNREACHABLE'), req_id, timeout=600
7e1b55
+        )
7e1b55
+        # get initial expiry date to compare later with renewed cert
7e1b55
+        initial_expiry = get_cert_expiry(
7e1b55
+            self.replicas[0],
7e1b55
+            paths.PKI_TOMCAT_ALIAS_DIR,
7e1b55
+            'Server-Cert cert-pki-ca'
7e1b55
         )
7e1b55
 
7e1b55
-        # LDAP/HTTP/PKINIT certs will be renewed automaticaly
7e1b55
-        # after moving date on replica. This 3, 1 CA cert,
7e1b55
-        # 1 RA agent cert. Check for total 5 valid certs.
7e1b55
-        check_status(self.replicas[0], 5, "MONITORING")
7e1b55
+        # check that HTTP,LDAP,PKINIT are renewed and in MONITORING state
7e1b55
+        instance = realm_to_serverid(self.master.domain.realm)
7e1b55
+        dirsrv_cert = paths.ETC_DIRSRV_SLAPD_INSTANCE_TEMPLATE % instance
7e1b55
+        for cert in (paths.KDC_CERT, paths.HTTPD_CERT_FILE):
7e1b55
+            cmd = self.replicas[0].run_command(
7e1b55
+                ['getcert', 'list', '-f', cert]
7e1b55
+            )
7e1b55
+            req_id = get_certmonger_fs_id(cmd.stdout_text)
7e1b55
+            tasks.wait_for_certmonger_status(
7e1b55
+                self.replicas[0], ('MONITORING'), req_id, timeout=600
7e1b55
+            )
7e1b55
 
7e1b55
-        # get the req ids of all certs to renew remaining
7e1b55
-        # certs by re-submitting it
7e1b55
-        result = self.replicas[0].run_command(['getcert', 'list'])
7e1b55
-        req_ids = re.findall(r'\d{14}', result.stdout_text)
7e1b55
+        cmd = self.replicas[0].run_command(
7e1b55
+            ['getcert', 'list', '-d', dirsrv_cert]
7e1b55
+        )
7e1b55
+        req_id = get_certmonger_fs_id(cmd.stdout_text)
7e1b55
+        tasks.wait_for_certmonger_status(
7e1b55
+            self.replicas[0], ('MONITORING'), req_id, timeout=600
7e1b55
+        )
7e1b55
 
7e1b55
-        # resubmit the certs to renew them
7e1b55
-        for req_id in req_ids:
7e1b55
+        # check if replication working fine
7e1b55
+        testuser = 'testuser1'
7e1b55
+        password = 'Secret@123'
7e1b55
+        stdin = (f"{self.master.config.admin_password}\n"
7e1b55
+                 f"{self.master.config.admin_password}\n"
7e1b55
+                 f"{self.master.config.admin_password}\n")
7e1b55
+        self.master.run_command(['kinit', 'admin'], stdin_text=stdin)
7e1b55
+        tasks.user_add(self.master, testuser, password=password)
7e1b55
+        self.replicas[0].run_command(['kinit', 'admin'], stdin_text=stdin)
7e1b55
+        self.replicas[0].run_command(['ipa', 'user-show', testuser])
7e1b55
+
7e1b55
+        # renew shared certificates by resubmitting to certmonger
7e1b55
+        cmd = self.replicas[0].run_command(
7e1b55
+            ['getcert', 'list', '-f', paths.RA_AGENT_PEM]
7e1b55
+        )
7e1b55
+        req_id = get_certmonger_fs_id(cmd.stdout_text)
7e1b55
+        if needs_resubmit(self.replicas[0], req_id):
7e1b55
             self.replicas[0].run_command(
7e1b55
                 ['getcert', 'resubmit', '-i', req_id]
7e1b55
             )
7e1b55
+            tasks.wait_for_certmonger_status(
7e1b55
+                self.replicas[0], ('MONITORING'), req_id, timeout=600
7e1b55
+            )
7e1b55
+        for cert_nick in ('auditSigningCert cert-pki-ca',
7e1b55
+                          'ocspSigningCert cert-pki-ca',
7e1b55
+                          'subsystemCert cert-pki-ca'):
7e1b55
+            cmd = self.replicas[0].run_command(
7e1b55
+                ['getcert', 'list',
7e1b55
+                 '-d', paths.PKI_TOMCAT_ALIAS_DIR,
7e1b55
+                 '-n', cert_nick]
7e1b55
+            )
7e1b55
+            req_id = get_certmonger_fs_id(cmd.stdout_text)
7e1b55
+            if needs_resubmit(self.replicas[0], req_id):
7e1b55
+                self.replicas[0].run_command(
7e1b55
+                    ['getcert', 'resubmit', '-i', req_id]
7e1b55
+                )
7e1b55
+                tasks.wait_for_certmonger_status(
7e1b55
+                    self.replicas[0], ('MONITORING'), req_id, timeout=600
7e1b55
+                )
7e1b55
 
7e1b55
-        check_status(self.master, 9, "MONITORING")
7e1b55
+        self.replicas[0].run_command(
7e1b55
+            ['ipa-cert-fix', '-v'], stdin_text='yes\n'
7e1b55
+        )
7e1b55
 
7e1b55
-        # move date back on replica and master
7e1b55
-        move_date(self.replicas[0], 'start', '-3years-1days')
7e1b55
-        move_date(self.master, 'start', '-3years-1days')
7e1b55
+        check_status(self.replicas[0], 9, "MONITORING")
7e1b55
+
7e1b55
+        # Sometimes certmonger takes time to update the cert status
7e1b55
+        # So check in nssdb instead of relying on getcert command
7e1b55
+        renewed_expiry = get_cert_expiry(
7e1b55
+            self.replicas[0],
7e1b55
+            paths.PKI_TOMCAT_ALIAS_DIR,
7e1b55
+            'Server-Cert cert-pki-ca'
7e1b55
+        )
7e1b55
+        assert renewed_expiry > initial_expiry
7e1b55
-- 
7e1b55
2.31.1
7e1b55