summaryrefslogtreecommitdiffstats
path: root/ipatests/test_xmlrpc
diff options
context:
space:
mode:
authorMilan KubĂ­k <mkubik@redhat.com>2016-09-12 14:54:40 +0200
committerMartin Babinsky <mbabinsk@redhat.com>2016-10-04 18:03:03 +0200
commit10b4b155b6b411ab339bce92c1a335b4914cfc1c (patch)
tree66da7a311968a86d22f2d840525effe97cb0963e /ipatests/test_xmlrpc
parent7eb78aa8dbc167c36869ddd6cfa525139aff7bbc (diff)
downloadfreeipa-10b4b155b6b411ab339bce92c1a335b4914cfc1c.tar.gz
freeipa-10b4b155b6b411ab339bce92c1a335b4914cfc1c.tar.xz
freeipa-10b4b155b6b411ab339bce92c1a335b4914cfc1c.zip
ipatests: Implement tests with CSRs requesting SAN
The patch implements several test cases testing the enforcement of CA ACLs on certificate requests with subject alternative names. https://fedorahosted.org/freeipa/ticket/6366 Reviewed-By: Martin Babinsky <mbabinsk@redhat.com>
Diffstat (limited to 'ipatests/test_xmlrpc')
-rw-r--r--ipatests/test_xmlrpc/test_caacl_profile_enforcement.py303
1 files changed, 301 insertions, 2 deletions
diff --git a/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py b/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py
index a73e84539..a5cc3acd3 100644
--- a/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py
+++ b/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py
@@ -9,13 +9,22 @@ import tempfile
import six
+from cryptography import x509
+from cryptography.x509.oid import NameOID
+from cryptography.hazmat.backends import default_backend
+from cryptography.hazmat.primitives import hashes, serialization
+from cryptography.hazmat.primitives.asymmetric import rsa
+
from ipalib import api, errors
from ipatests.util import (
- prepare_config, unlock_principal_password, change_principal)
+ prepare_config, unlock_principal_password, change_principal,
+ host_keytab)
from ipatests.test_xmlrpc.xmlrpc_test import XMLRPC_test
from ipatests.test_xmlrpc.tracker.certprofile_plugin import CertprofileTracker
from ipatests.test_xmlrpc.tracker.caacl_plugin import CAACLTracker
from ipatests.test_xmlrpc.tracker.ca_plugin import CATracker
+from ipatests.test_xmlrpc.tracker.host_plugin import HostTracker
+from ipatests.test_xmlrpc.tracker.service_plugin import ServiceTracker
from ipapython.ipautil import run
@@ -29,7 +38,6 @@ SMIME_MOD_CONSTR_PROFILE_TEMPLATE = os.path.join(BASE_DIR, 'data/smime-mod.cfg.t
CERT_OPENSSL_CONFIG_TEMPLATE = os.path.join(BASE_DIR, 'data/usercert.conf.tmpl')
CERT_RSA_PRIVATE_KEY_PATH = os.path.join(BASE_DIR, 'data/usercert-priv-key.pem')
-
SMIME_USER_INIT_PW = u'Change123'
SMIME_USER_PW = u'Secret123'
@@ -354,3 +362,294 @@ class TestCertSignMIMEwithSubCA(XMLRPC_test):
with change_principal(smime_user, SMIME_USER_PW):
api.Command.cert_request(csr, principal=smime_user_principal,
cacn=smime_signing_ca.name)
+
+
+@pytest.fixture(scope='class')
+def santest_subca(request):
+ name = u'default-profile-subca'
+ subject = u'CN={},O=test'.format(name)
+ tr = CATracker(name, subject)
+ return tr.make_fixture(request)
+
+
+@pytest.fixture(scope='class')
+def santest_subca_acl(request):
+ tr = CAACLTracker(u'default_profile_subca')
+ return tr.make_fixture(request)
+
+
+@pytest.fixture(scope='class')
+def santest_host_1(request):
+ tr = HostTracker(u'santest-host-1')
+ return tr.make_fixture(request)
+
+
+@pytest.fixture(scope='class')
+def santest_host_2(request):
+ tr = HostTracker(u'santest-host-2')
+ return tr.make_fixture(request)
+
+
+@pytest.fixture(scope='class')
+def santest_service_host_1(request, santest_host_1):
+ tr = ServiceTracker(u'srv', santest_host_1.name)
+ return tr.make_fixture(request)
+
+
+@pytest.fixture(scope='class')
+def santest_service_host_2(request, santest_host_2):
+ tr = ServiceTracker(u'srv', santest_host_2.name)
+ return tr.make_fixture(request)
+
+
+@pytest.fixture
+def santest_csr(request, santest_host_1, santest_host_2):
+ backend = default_backend()
+ pkey = rsa.generate_private_key(
+ public_exponent=65537,
+ key_size=2048,
+ backend=backend
+ )
+
+ csr = x509.CertificateSigningRequestBuilder().subject_name(x509.Name([
+ x509.NameAttribute(NameOID.COMMON_NAME, santest_host_1.fqdn),
+ x509.NameAttribute(NameOID.ORGANIZATION_NAME, api.env.realm)
+ ])).add_extension(x509.SubjectAlternativeName([
+ x509.DNSName(santest_host_1.name),
+ x509.DNSName(santest_host_2.name)
+ ]), False
+ ).add_extension(
+ x509.BasicConstraints(ca=False, path_length=None),
+ True
+ ).add_extension(
+ x509.KeyUsage(
+ digital_signature=True, content_commitment=True,
+ key_encipherment=True, data_encipherment=False,
+ key_agreement=False, key_cert_sign=False,
+ crl_sign=False, encipher_only=False,
+ decipher_only=False
+ ),
+ False
+ ).sign(
+ pkey, hashes.SHA256(), backend
+ ).public_bytes(serialization.Encoding.PEM)
+
+ return unicode(csr)
+
+
+class CAACLEnforcementOnCertBase(XMLRPC_test):
+ """Base setup class for tests with SAN in CSR
+
+ The class prepares an environment for test cases based
+ on evaluation of ACLs and fields requested in a CSR.
+
+ The class creates following entries:
+
+ * two host entries
+ * santest-host-1
+ * santest-host-2
+ * two service entries
+ * srv/santest-host-1
+ * srv/santest-host-2
+ * Sub CA
+ * default-profile-subca
+
+ This one is created in order not to need
+ to re-import caIPAServiceCert profile
+ * CA ACL
+ * default_profile_subca
+
+ After executing the methods the CA ACL should contain:
+
+ CA ACL:
+ * santest-host-1 -- host
+ * srv/santest-host-1 -- service
+ * default-profile-subca -- CA
+ * caIPAServiceCert -- profile
+ """
+
+ def test_prepare_caacl_hosts(self, santest_subca_acl,
+ santest_host_1, santest_host_2):
+ santest_subca_acl.ensure_exists()
+ santest_host_1.ensure_exists()
+ santest_host_2.ensure_exists()
+ santest_subca_acl.add_host(santest_host_1.name)
+
+ def test_prepare_caacl_CA(self, santest_subca_acl, santest_subca):
+ santest_subca.ensure_exists()
+ santest_subca_acl.add_ca(santest_subca.name)
+
+ def test_prepare_caacl_profile(self, santest_subca_acl):
+ santest_subca_acl.add_profile(u'caIPAserviceCert')
+
+ def test_prepare_caacl_services(self, santest_subca_acl,
+ santest_service_host_1,
+ santest_service_host_2):
+ santest_service_host_1.ensure_exists()
+ santest_service_host_2.ensure_exists()
+
+ santest_subca_acl.add_service(santest_service_host_1.name)
+
+
+@pytest.mark.tier1
+class TestSignCertificateWithInvalidSAN(CAACLEnforcementOnCertBase):
+ """Sign certificate request witn an invalid SAN entry
+
+ Using the environment prepared by the base class, ask to sign
+ a certificate request for a service managed by one host only.
+ The CSR contains another domain name in SAN extension that should
+ be refused as the host does not have rights to manage the service.
+ """
+ def test_request_cert_with_not_allowed_SAN(
+ self, santest_subca, santest_host_1, santest_host_2,
+ santest_service_host_1, santest_csr):
+
+ with host_keytab(santest_host_1.name) as keytab_filename:
+ with change_principal(santest_host_1.attrs['krbcanonicalname'][0],
+ keytab=keytab_filename):
+ with pytest.raises(errors.ACIError):
+ api.Command.cert_request(
+ santest_csr,
+ principal=santest_service_host_1.name,
+ cacn=santest_subca.name
+ )
+
+
+@pytest.mark.tier1
+class TestSignServiceCertManagedByMultipleHosts(CAACLEnforcementOnCertBase):
+ """ Sign certificate request with multiple subject alternative names
+
+ Using the environment of the base class, modify the service to be managed
+ by the second host. Then request a certificate for the service with SAN
+ of the second host in CSR. The certificate should be issued.
+ """
+ def test_make_service_managed_by_each_host(self,
+ santest_host_1,
+ santest_service_host_1,
+ santest_host_2,
+ santest_service_host_2):
+ api.Command['service_add_host'](
+ santest_service_host_1.name, host=[santest_host_2.fqdn]
+ )
+ api.Command['service_add_host'](
+ santest_service_host_2.name, host=[santest_host_1.fqdn]
+ )
+
+ def test_extend_the_ca_acl(self, santest_subca_acl, santest_host_2,
+ santest_service_host_2):
+ santest_subca_acl.add_host(santest_host_2.name)
+ santest_subca_acl.add_service(santest_service_host_2.name)
+
+ def test_request_cert_with_additional_host(
+ self, santest_subca, santest_host_1, santest_host_2,
+ santest_service_host_1, santest_csr):
+
+ with host_keytab(santest_host_1.name) as keytab_filename:
+ with change_principal(santest_host_1.attrs['krbcanonicalname'][0],
+ keytab=keytab_filename):
+ api.Command.cert_request(
+ santest_csr,
+ principal=santest_service_host_1.name,
+ cacn=santest_subca.name
+ )
+
+
+@pytest.mark.tier1
+class TestSignServiceCertWithoutSANServiceInACL(CAACLEnforcementOnCertBase):
+ """ Sign certificate request with multiple subject alternative names
+
+ This test case doesn't have the service hosted on a host in SAN
+ in the CA ACL. The assumption is that the issuance will fail.
+ """
+ def test_make_service_managed_by_each_host(self,
+ santest_host_1,
+ santest_service_host_1,
+ santest_host_2,
+ santest_service_host_2):
+ api.Command['service_add_host'](
+ santest_service_host_1.name, host=[santest_host_2.fqdn]
+ )
+ api.Command['service_add_host'](
+ santest_service_host_2.name, host=[santest_host_1.fqdn]
+ )
+
+ def test_extend_the_ca_acl(self, santest_subca_acl, santest_host_2,
+ santest_service_host_2):
+ santest_subca_acl.add_host(santest_host_2.name)
+
+ def test_request_cert_with_additional_host(
+ self, santest_subca, santest_host_1, santest_host_2,
+ santest_service_host_1, santest_csr):
+
+ with host_keytab(santest_host_1.name) as keytab_filename:
+ with change_principal(santest_host_1.attrs['krbcanonicalname'][0],
+ keytab=keytab_filename):
+ with pytest.raises(errors.ACIError):
+ api.Command.cert_request(
+ santest_csr,
+ principal=santest_service_host_1.name,
+ cacn=santest_subca.name
+ )
+
+
+@pytest.mark.tier1
+class TestManagedByACIOnCertRequest(CAACLEnforcementOnCertBase):
+ """Test issuence of a certificate by external host
+
+ The test verifies that the managed by attribute of a service
+ is enforced on certificate signing.
+
+ The two test cases test the issuance of a service certificate
+ to a service by a second host.
+
+ In one of them the service is not managed by the principal
+ requesting the certificate, thus the issuance should fail.
+
+ The second one makes the service managed, thus the certificate
+ should be issued.
+ """
+ def test_update_the_caacl(self,
+ santest_subca_acl,
+ santest_host_2,
+ santest_service_host_2):
+ santest_subca_acl.add_host(santest_host_2.name)
+ santest_subca_acl.add_service(santest_service_host_2.name)
+
+ def test_issuing_service_cert_by_unrelated_host(self,
+ santest_subca,
+ santest_host_1,
+ santest_host_2,
+ santest_service_host_1,
+ santest_csr):
+
+ with host_keytab(santest_host_2.name) as keytab_filename:
+ with change_principal(santest_host_2.attrs['krbcanonicalname'][0],
+ keytab=keytab_filename):
+ with pytest.raises(errors.ACIError):
+ api.Command.cert_request(
+ santest_csr,
+ principal=santest_service_host_1.name,
+ cacn=santest_subca.name
+ )
+
+ def test_issuing_service_cert_by_related_host(self,
+ santest_subca,
+ santest_host_1,
+ santest_host_2,
+ santest_service_host_1,
+ santest_csr):
+ # The test case alters the previous state by making
+ # the service managed by the second host.
+ # Then it attempts to request the certificate again
+ api.Command['service_add_host'](
+ santest_service_host_1.name, host=[santest_host_2.fqdn]
+ )
+
+ with host_keytab(santest_host_2.name) as keytab_filename:
+ with change_principal(santest_host_2.attrs['krbcanonicalname'][0],
+ keytab=keytab_filename):
+ api.Command.cert_request(
+ santest_csr,
+ principal=santest_service_host_1.name,
+ cacn=santest_subca.name
+ )