|
|
cf0866 |
From 94ca49d991b3f5bb404533f84970a1b2485d9cc8 Mon Sep 17 00:00:00 2001
|
|
|
cf0866 |
From: Antonio Torres <antorres@redhat.com>
|
|
|
cf0866 |
Date: Fri, 23 Apr 2021 17:48:14 +0200
|
|
|
cf0866 |
Subject: [PATCH] Add tests for certificate mismatch detection
|
|
|
cf0866 |
|
|
|
cf0866 |
Add tests for the IPACertMatchCheck and IPADogtagCertsMatchCheck plugins.
|
|
|
cf0866 |
|
|
|
cf0866 |
Related: https://bugzilla.redhat.com/show_bug.cgi?id=1886770
|
|
|
cf0866 |
Signed-off-by: Antonio Torres <antorres@redhat.com>
|
|
|
cf0866 |
---
|
|
|
cf0866 |
tests/test_ipa_cert_match.py | 282 +++++++++++++++++++++++++++++++++++
|
|
|
cf0866 |
1 file changed, 282 insertions(+)
|
|
|
cf0866 |
create mode 100644 tests/test_ipa_cert_match.py
|
|
|
cf0866 |
|
|
|
cf0866 |
diff --git a/tests/test_ipa_cert_match.py b/tests/test_ipa_cert_match.py
|
|
|
cf0866 |
new file mode 100644
|
|
|
cf0866 |
index 0000000..460e61a
|
|
|
cf0866 |
--- /dev/null
|
|
|
cf0866 |
+++ b/tests/test_ipa_cert_match.py
|
|
|
cf0866 |
@@ -0,0 +1,282 @@
|
|
|
cf0866 |
+#
|
|
|
cf0866 |
+# Copyright (C) 2021 FreeIPA Contributors see COPYING for license
|
|
|
cf0866 |
+#
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+from util import capture_results, m_api, CAInstance, KRAInstance
|
|
|
cf0866 |
+from base import BaseTest
|
|
|
cf0866 |
+from ipahealthcheck.core import config, constants
|
|
|
cf0866 |
+from ipahealthcheck.ipa.plugin import registry
|
|
|
cf0866 |
+from ipahealthcheck.ipa.certs import IPACertMatchCheck
|
|
|
cf0866 |
+from ipahealthcheck.ipa.certs import IPADogtagCertsMatchCheck
|
|
|
cf0866 |
+from unittest.mock import Mock, patch
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+from ipalib import errors
|
|
|
cf0866 |
+from ipapython.dn import DN
|
|
|
cf0866 |
+from ipapython.ipaldap import LDAPClient, LDAPEntry
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+class IPACertificate:
|
|
|
cf0866 |
+ def __init__(self, serial_number=1):
|
|
|
cf0866 |
+ self.serial_number = serial_number
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ def __eq__(self, other):
|
|
|
cf0866 |
+ return self.serial_number == other.serial_number
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ def __hash__(self):
|
|
|
cf0866 |
+ return hash(self.serial_number)
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+class mock_ldap:
|
|
|
cf0866 |
+ SCOPE_BASE = 1
|
|
|
cf0866 |
+ SCOPE_ONELEVEL = 2
|
|
|
cf0866 |
+ SCOPE_SUBTREE = 4
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ def __init__(self, entries):
|
|
|
cf0866 |
+ """Initialize the results that we will return from get_entry"""
|
|
|
cf0866 |
+ self.results = {entry.dn: entry for entry in entries}
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ def get_entry(self, dn, attrs_list=None, time_limit=None,
|
|
|
cf0866 |
+ size_limit=None, get_effective_rights=False):
|
|
|
cf0866 |
+ if self.results is None:
|
|
|
cf0866 |
+ raise errors.NotFound(reason='test')
|
|
|
cf0866 |
+ return self.results[dn]
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ def get_entries(self, base_dn, scope=SCOPE_SUBTREE, filter=None,
|
|
|
cf0866 |
+ attrs_list=None, get_effective_rights=False, **kwargs):
|
|
|
cf0866 |
+ if self.results is None:
|
|
|
cf0866 |
+ raise errors.NotFound(reason='test')
|
|
|
cf0866 |
+ return self.results.values()
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+class mock_ldap_conn:
|
|
|
cf0866 |
+ def set_option(self, option, invalue):
|
|
|
cf0866 |
+ pass
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ def search_s(self, base, scope, filterstr=None,
|
|
|
cf0866 |
+ attrlist=None, attrsonly=0):
|
|
|
cf0866 |
+ return tuple()
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+class mock_CertDB:
|
|
|
cf0866 |
+ def __init__(self, trust):
|
|
|
cf0866 |
+ """A dict of nickname + NSSdb trust flags"""
|
|
|
cf0866 |
+ self.trust = trust
|
|
|
cf0866 |
+ self.secdir = '/foo/bar/testdir'
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ def get_cert_from_db(self, nickname):
|
|
|
cf0866 |
+ if nickname not in self.trust.keys():
|
|
|
cf0866 |
+ raise errors.NotFound(reason='test')
|
|
|
cf0866 |
+ return IPACertificate()
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ def run_certutil(self, args, capture_output):
|
|
|
cf0866 |
+ class RunResult:
|
|
|
cf0866 |
+ def __init__(self, output):
|
|
|
cf0866 |
+ self.raw_output = output
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ return RunResult(b'test output')
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+class TestIPACertMatch(BaseTest):
|
|
|
cf0866 |
+ patches = {
|
|
|
cf0866 |
+ 'ldap.initialize':
|
|
|
cf0866 |
+ Mock(return_value=mock_ldap_conn())
|
|
|
cf0866 |
+ }
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ @patch('ipalib.x509.load_certificate_list_from_file')
|
|
|
cf0866 |
+ @patch('ipaserver.install.certs.CertDB')
|
|
|
cf0866 |
+ def test_certs_match_ok(self, mock_certdb, mock_load_cert):
|
|
|
cf0866 |
+ """ Ensure match check is ok"""
|
|
|
cf0866 |
+ fake_conn = LDAPClient('ldap://localhost', no_schema=True)
|
|
|
cf0866 |
+ cacertentry = LDAPEntry(fake_conn,
|
|
|
cf0866 |
+ DN('cn=%s IPA CA' % m_api.env.realm,
|
|
|
cf0866 |
+ 'cn=certificates,cn=ipa,cn=etc',
|
|
|
cf0866 |
+ m_api.env.basedn),
|
|
|
cf0866 |
+ CACertificate=[IPACertificate()])
|
|
|
cf0866 |
+ trust = {
|
|
|
cf0866 |
+ ('%s IPA CA' % m_api.env.realm): 'u,u,u'
|
|
|
cf0866 |
+ }
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ mock_certdb.return_value = mock_CertDB(trust)
|
|
|
cf0866 |
+ mock_load_cert.return_value = [IPACertificate()]
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ framework = object()
|
|
|
cf0866 |
+ registry.initialize(framework, config.Config())
|
|
|
cf0866 |
+ f = IPACertMatchCheck(registry)
|
|
|
cf0866 |
+ f.conn = mock_ldap([cacertentry])
|
|
|
cf0866 |
+ self.results = capture_results(f)
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ assert len(self.results) == 3
|
|
|
cf0866 |
+ for result in self.results.results:
|
|
|
cf0866 |
+ assert result.result == constants.SUCCESS
|
|
|
cf0866 |
+ assert result.source == 'ipahealthcheck.ipa.certs'
|
|
|
cf0866 |
+ assert result.check == 'IPACertMatchCheck'
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ @patch('ipalib.x509.load_certificate_list_from_file')
|
|
|
cf0866 |
+ @patch('ipaserver.install.certs.CertDB')
|
|
|
cf0866 |
+ def test_etc_cacert_mismatch(self, mock_certdb, mock_load_cert):
|
|
|
cf0866 |
+ """ Test mismatch with /etc/ipa/ca.crt """
|
|
|
cf0866 |
+ fake_conn = LDAPClient('ldap://localhost', no_schema=True)
|
|
|
cf0866 |
+ cacertentry = LDAPEntry(fake_conn,
|
|
|
cf0866 |
+ DN('cn=%s IPA CA' % m_api.env.realm,
|
|
|
cf0866 |
+ 'cn=certificates,cn=ipa,cn=etc',
|
|
|
cf0866 |
+ m_api.env.basedn),
|
|
|
cf0866 |
+ CACertificate=[IPACertificate()])
|
|
|
cf0866 |
+ trust = {
|
|
|
cf0866 |
+ ('%s IPA CA' % m_api.env.realm): 'u,u,u'
|
|
|
cf0866 |
+ }
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ mock_certdb.return_value = mock_CertDB(trust)
|
|
|
cf0866 |
+ mock_load_cert.return_value = [IPACertificate(serial_number=2)]
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ framework = object()
|
|
|
cf0866 |
+ registry.initialize(framework, config.Config())
|
|
|
cf0866 |
+ f = IPACertMatchCheck(registry)
|
|
|
cf0866 |
+ f.conn = mock_ldap([cacertentry])
|
|
|
cf0866 |
+ self.results = capture_results(f)
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ assert len(self.results) == 3
|
|
|
cf0866 |
+ result = self.results.results[0]
|
|
|
cf0866 |
+ assert result.result == constants.ERROR
|
|
|
cf0866 |
+ assert result.source == 'ipahealthcheck.ipa.certs'
|
|
|
cf0866 |
+ assert result.check == 'IPACertMatchCheck'
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ @patch('ipaserver.install.cainstance.CAInstance')
|
|
|
cf0866 |
+ def test_cacert_caless(self, mock_cainstance):
|
|
|
cf0866 |
+ """Nothing to check if the master is CALess"""
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ mock_cainstance.return_value = CAInstance(False)
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ framework = object()
|
|
|
cf0866 |
+ registry.initialize(framework, config)
|
|
|
cf0866 |
+ f = IPACertMatchCheck(registry)
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ self.results = capture_results(f)
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ assert len(self.results) == 0
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+class TestIPADogtagCertMatch(BaseTest):
|
|
|
cf0866 |
+ patches = {
|
|
|
cf0866 |
+ 'ipaserver.install.krainstance.KRAInstance':
|
|
|
cf0866 |
+ Mock(return_value=KRAInstance()),
|
|
|
cf0866 |
+ }
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ @patch('ipaserver.install.certs.CertDB')
|
|
|
cf0866 |
+ def test_certs_match_ok(self, mock_certdb):
|
|
|
cf0866 |
+ """ Ensure match check is ok"""
|
|
|
cf0866 |
+ fake_conn = LDAPClient('ldap://localhost', no_schema=True)
|
|
|
cf0866 |
+ pkidbentry = LDAPEntry(fake_conn,
|
|
|
cf0866 |
+ DN('uid=pkidbuser,ou=people,o=ipaca'),
|
|
|
cf0866 |
+ userCertificate=[IPACertificate()],
|
|
|
cf0866 |
+ subjectName=['test'])
|
|
|
cf0866 |
+ casignentry = LDAPEntry(fake_conn,
|
|
|
cf0866 |
+ DN('cn=%s IPA CA' % m_api.env.realm,
|
|
|
cf0866 |
+ 'cn=certificates,cn=ipa,cn=etc',
|
|
|
cf0866 |
+ m_api.env.basedn),
|
|
|
cf0866 |
+ CACertificate=[IPACertificate()],
|
|
|
cf0866 |
+ userCertificate=[IPACertificate()],
|
|
|
cf0866 |
+ subjectName=['test'])
|
|
|
cf0866 |
+ ldap_entries = [pkidbentry, casignentry]
|
|
|
cf0866 |
+ trust = {
|
|
|
cf0866 |
+ 'ocspSigningCert cert-pki-ca': 'u,u,u',
|
|
|
cf0866 |
+ 'caSigningCert cert-pki-ca': 'u,u,u',
|
|
|
cf0866 |
+ 'subsystemCert cert-pki-ca': 'u,u,u',
|
|
|
cf0866 |
+ 'auditSigningCert cert-pki-ca': 'u,u,Pu',
|
|
|
cf0866 |
+ 'Server-Cert cert-pki-ca': 'u,u,u',
|
|
|
cf0866 |
+ 'transportCert cert-pki-kra': 'u,u,u',
|
|
|
cf0866 |
+ 'storageCert cert-pki-kra': 'u,u,u',
|
|
|
cf0866 |
+ 'auditSigningCert cert-pki-kra': 'u,u,Pu',
|
|
|
cf0866 |
+ }
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ dogtag_entries_subjects = (
|
|
|
cf0866 |
+ 'CN=OCSP Subsystem,O=%s' % m_api.env.realm,
|
|
|
cf0866 |
+ 'CN=CA Subsystem,O=%s' % m_api.env.realm,
|
|
|
cf0866 |
+ 'CN=CA Audit,O=%s' % m_api.env.realm,
|
|
|
cf0866 |
+ 'CN=%s,O=%s' % (m_api.env.host, m_api.env.realm),
|
|
|
cf0866 |
+ 'CN=KRA Transport Certificate,O=%s' % m_api.env.realm,
|
|
|
cf0866 |
+ 'CN=KRA Storage Certificate,O=%s' % m_api.env.realm,
|
|
|
cf0866 |
+ 'CN=KRA Audit,O=%s' % m_api.env.realm,
|
|
|
cf0866 |
+ )
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ for i, subject in enumerate(dogtag_entries_subjects):
|
|
|
cf0866 |
+ entry = LDAPEntry(fake_conn,
|
|
|
cf0866 |
+ DN('cn=%i,ou=certificateRepository' % i,
|
|
|
cf0866 |
+ 'ou=ca,o=ipaca'),
|
|
|
cf0866 |
+ userCertificate=[IPACertificate()],
|
|
|
cf0866 |
+ subjectName=[subject])
|
|
|
cf0866 |
+ ldap_entries.append(entry)
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ mock_certdb.return_value = mock_CertDB(trust)
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ framework = object()
|
|
|
cf0866 |
+ registry.initialize(framework, config.Config())
|
|
|
cf0866 |
+ f = IPADogtagCertsMatchCheck(registry)
|
|
|
cf0866 |
+ f.conn = mock_ldap(ldap_entries)
|
|
|
cf0866 |
+ self.results = capture_results(f)
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ assert len(self.results) == 3
|
|
|
cf0866 |
+ for result in self.results.results:
|
|
|
cf0866 |
+ assert result.result == constants.SUCCESS
|
|
|
cf0866 |
+ assert result.source == 'ipahealthcheck.ipa.certs'
|
|
|
cf0866 |
+ assert result.check == 'IPADogtagCertsMatchCheck'
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ @patch('ipaserver.install.certs.CertDB')
|
|
|
cf0866 |
+ def test_certs_mismatch(self, mock_certdb):
|
|
|
cf0866 |
+ """ Ensure mismatches are detected"""
|
|
|
cf0866 |
+ fake_conn = LDAPClient('ldap://localhost', no_schema=True)
|
|
|
cf0866 |
+ pkidbentry = LDAPEntry(fake_conn,
|
|
|
cf0866 |
+ DN('uid=pkidbuser,ou=people,o=ipaca'),
|
|
|
cf0866 |
+ userCertificate=[IPACertificate(
|
|
|
cf0866 |
+ serial_number=2
|
|
|
cf0866 |
+ )],
|
|
|
cf0866 |
+ subjectName=['test'])
|
|
|
cf0866 |
+ casignentry = LDAPEntry(fake_conn,
|
|
|
cf0866 |
+ DN('cn=%s IPA CA' % m_api.env.realm,
|
|
|
cf0866 |
+ 'cn=certificates,cn=ipa,cn=etc',
|
|
|
cf0866 |
+ m_api.env.basedn),
|
|
|
cf0866 |
+ CACertificate=[IPACertificate()],
|
|
|
cf0866 |
+ userCertificate=[IPACertificate()],
|
|
|
cf0866 |
+ subjectName=['test'])
|
|
|
cf0866 |
+ ldap_entries = [pkidbentry, casignentry]
|
|
|
cf0866 |
+ trust = {
|
|
|
cf0866 |
+ 'ocspSigningCert cert-pki-ca': 'u,u,u',
|
|
|
cf0866 |
+ 'caSigningCert cert-pki-ca': 'u,u,u',
|
|
|
cf0866 |
+ 'subsystemCert cert-pki-ca': 'u,u,u',
|
|
|
cf0866 |
+ 'auditSigningCert cert-pki-ca': 'u,u,Pu',
|
|
|
cf0866 |
+ 'Server-Cert cert-pki-ca': 'u,u,u',
|
|
|
cf0866 |
+ 'transportCert cert-pki-kra': 'u,u,u',
|
|
|
cf0866 |
+ 'storageCert cert-pki-kra': 'u,u,u',
|
|
|
cf0866 |
+ 'auditSigningCert cert-pki-kra': 'u,u,Pu',
|
|
|
cf0866 |
+ }
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ dogtag_entries_subjects = (
|
|
|
cf0866 |
+ 'CN=OCSP Subsystem,O=%s' % m_api.env.realm,
|
|
|
cf0866 |
+ 'CN=CA Subsystem,O=%s' % m_api.env.realm,
|
|
|
cf0866 |
+ 'CN=CA Audit,O=%s' % m_api.env.realm,
|
|
|
cf0866 |
+ 'CN=%s,O=%s' % (m_api.env.host, m_api.env.realm),
|
|
|
cf0866 |
+ 'CN=KRA Transport Certificate,O=%s' % m_api.env.realm,
|
|
|
cf0866 |
+ 'CN=KRA Storage Certificate,O=%s' % m_api.env.realm,
|
|
|
cf0866 |
+ 'CN=KRA Audit,O=%s' % m_api.env.realm,
|
|
|
cf0866 |
+ )
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ for i, subject in enumerate(dogtag_entries_subjects):
|
|
|
cf0866 |
+ entry = LDAPEntry(fake_conn,
|
|
|
cf0866 |
+ DN('cn=%i,ou=certificateRepository' % i,
|
|
|
cf0866 |
+ 'ou=ca,o=ipaca'),
|
|
|
cf0866 |
+ userCertificate=[IPACertificate()],
|
|
|
cf0866 |
+ subjectName=[subject])
|
|
|
cf0866 |
+ ldap_entries.append(entry)
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ mock_certdb.return_value = mock_CertDB(trust)
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ framework = object()
|
|
|
cf0866 |
+ registry.initialize(framework, config.Config())
|
|
|
cf0866 |
+ f = IPADogtagCertsMatchCheck(registry)
|
|
|
cf0866 |
+ f.conn = mock_ldap(ldap_entries)
|
|
|
cf0866 |
+ self.results = capture_results(f)
|
|
|
cf0866 |
+
|
|
|
cf0866 |
+ assert len(self.results) == 3
|
|
|
cf0866 |
+ result = self.results.results[0]
|
|
|
cf0866 |
+ assert result.result == constants.ERROR
|
|
|
cf0866 |
+ assert result.source == 'ipahealthcheck.ipa.certs'
|
|
|
cf0866 |
+ assert result.check == 'IPADogtagCertsMatchCheck'
|
|
|
cf0866 |
--
|
|
|
cf0866 |
2.26.3
|
|
|
cf0866 |
|