Hi Fraser and list,

I have made changes to the test plan on the wiki [1] according to the
information in "[Testplan review] Sub CAs" thread.

I also implemented the tests in the test plan:

patch 0038 - CATracker and CA CRUD test
patch 0039 - extension to CA ACL test
patch 0040 - functional test with ACLs and certificate profile, reusing my previous S/MIME based tests. This patch also tests for the cert-request behavior when profile ID or CA cn are ommited.

The tests ATM do not verify the Issuer name in the certificate itself, just from the ipa entry of the certificate.

Fraser, could you please verify my reasoning behind the test cases for cert-request in the patch 40?

[1]: http://www.freeipa.org/page/V4/Sub-CAs/Test_Plan

Cheers

--
Milan Kubik

From 83153e3c7c4a28ba170633054b59b2d6a70807c0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Milan=20Kub=C3=ADk?= <mku...@redhat.com>
Date: Fri, 17 Jun 2016 12:20:55 +0200
Subject: [PATCH 1/3] ipatests: Tracker implementation for Sub CA feature

The patch implements Tracker subclass for CA plugin
and the basic CRUD tests for the plugin entries.

https://fedorahosted.org/freeipa/ticket/4559
---
 ipatests/test_xmlrpc/objectclasses.py     |   5 +
 ipatests/test_xmlrpc/test_ca_plugin.py    | 176 ++++++++++++++++++++++++++++++
 ipatests/test_xmlrpc/tracker/ca_plugin.py | 126 +++++++++++++++++++++
 ipatests/test_xmlrpc/xmlrpc_test.py       |   3 +
 4 files changed, 310 insertions(+)
 create mode 100644 ipatests/test_xmlrpc/test_ca_plugin.py
 create mode 100644 ipatests/test_xmlrpc/tracker/ca_plugin.py

diff --git a/ipatests/test_xmlrpc/objectclasses.py b/ipatests/test_xmlrpc/objectclasses.py
index 134a08803f3abca1124c4d26274d9e3fc981b941..1ea020b18f975f717eb9d9d5399d8e9fb40264cb 100644
--- a/ipatests/test_xmlrpc/objectclasses.py
+++ b/ipatests/test_xmlrpc/objectclasses.py
@@ -222,3 +222,8 @@ caacl = [
     u'ipaassociation',
     u'ipacaacl'
 ]
+
+ca = [
+    u'top',
+    u'ipaca',
+]
diff --git a/ipatests/test_xmlrpc/test_ca_plugin.py b/ipatests/test_xmlrpc/test_ca_plugin.py
new file mode 100644
index 0000000000000000000000000000000000000000..a638a0c9a5a611687d4ae707f4b067bef2ef2229
--- /dev/null
+++ b/ipatests/test_xmlrpc/test_ca_plugin.py
@@ -0,0 +1,176 @@
+#
+# Copyright (C) 2016  FreeIPA Contributors see COPYING for license
+#
+
+"""
+Test the `ipalib.plugins.ca` module.
+"""
+
+import pytest
+
+from ipalib import errors
+from ipatests.test_xmlrpc.xmlrpc_test import XMLRPC_test, fuzzy_issuer
+
+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
+
+
+@pytest.fixture(scope='module')
+def default_profile(request):
+    name = 'caIPAserviceCert'
+    desc = u'Standard profile for network services'
+    tracker = CertprofileTracker(name, store=True, desc=desc)
+    tracker.track_create()
+    return tracker
+
+
+@pytest.fixture(scope='module')
+def default_acl(request):
+    name = u'hosts_services_caIPAserviceCert'
+    tracker = CAACLTracker(name, service_category=u'all', host_category=u'all')
+    tracker.track_create()
+    tracker.attrs.update(
+        {u'ipamembercertprofile_certprofile': [u'caIPAserviceCert']})
+    return tracker
+
+
+@pytest.fixture(scope='module')
+def default_ca(request):
+    name = u'ipa'
+    desc = u'IPA CA'
+    tracker = CATracker(name, fuzzy_issuer, desc=desc)
+    tracker.track_create()
+    return tracker
+
+
+@pytest.fixture(scope='class')
+def crud_subca(request):
+    name = u'crud-subca'
+    subject = u'CN=crud subca test,O=crud testing inc'
+    tracker = CATracker(name, subject)
+
+    return tracker.make_fixture(request)
+
+
+@pytest.fixture(scope='class')
+def subject_conflict_subca(request):
+    name = u'crud-subca-2'
+    subject = u'CN=crud subca test,O=crud testing inc'
+    tracker = CATracker(name, subject)
+
+    return tracker.make_fixture(request)
+
+
+@pytest.mark.tier0
+class TestDefaultCA(XMLRPC_test):
+    def test_default_ca_present(self, default_ca):
+        default_ca.retrieve()
+
+    def test_default_ca_delete(self, default_ca):
+        with pytest.raises(errors.ProtectedEntryError):
+            default_ca.delete()
+
+
+@pytest.mark.tier1
+class TestCAbasicCRUD(XMLRPC_test):
+
+    ATTR_ERROR_MSG = u'attribute is not configurable'
+
+    def test_create(self, crud_subca):
+        crud_subca.create()
+
+    def test_retrieve(self, crud_subca):
+        crud_subca.retrieve()
+
+    def test_retrieve_all(self, crud_subca):
+        crud_subca.retrieve(all=True)
+
+    def test_delete(self, crud_subca):
+        crud_subca.delete()
+
+    def test_find(self, crud_subca):
+        crud_subca.ensure_exists()
+        crud_subca.find()
+
+    def test_modify_description(self, crud_subca):
+        new_desc = u'updated CA description'
+        crud_subca.update(
+            dict(
+                description=new_desc,
+            ),
+            expected_updates=dict(
+                description=[new_desc]
+            )
+        )
+
+    def test_modify_issuerdn(self, crud_subca):
+        bogus_issuer = u'ipacaissuerdn="cn=phony issuer,o=phony industries'
+        cmd = crud_subca.make_update_command(
+            updates=dict(setattr=bogus_issuer)
+        )
+
+        with pytest.raises(errors.ValidationError) as error:
+            cmd()
+
+        assert self.ATTR_ERROR_MSG in str(error.value)
+
+    def test_modify_subjectdn(self, crud_subca):
+        bogus_subject = u'ipacasubjectdn="cn=phony subject,o=phony industries'
+        cmd = crud_subca.make_update_command(
+            updates=dict(setattr=bogus_subject)
+        )
+
+        with pytest.raises(errors.ValidationError) as error:
+            cmd()
+
+        assert self.ATTR_ERROR_MSG in str(error.value)
+
+    def test_delete_subjectdn(self, crud_subca):
+        cmd = crud_subca.make_update_command(
+            updates=dict(delattr=u'ipacasubjectdn=%s'
+                         % crud_subca.ipasubjectdn)
+        )
+
+        with pytest.raises(errors.ValidationError) as error:
+            cmd()
+
+        assert self.ATTR_ERROR_MSG in str(error.value)
+
+    def test_add_bogus_subjectdn(self, crud_subca):
+        bogus_subject = u'ipacasubjectdn="cn=phony subject,o=phony industries'
+        cmd = crud_subca.make_update_command(
+            updates=dict(addattr=bogus_subject)
+        )
+
+        with pytest.raises(errors.ValidationError) as error:
+            cmd()
+
+        assert self.ATTR_ERROR_MSG in str(error.value)
+
+    def test_add_bogus_issuerdn(self, crud_subca):
+        bogus_issuer = u'ipacaissuerdn="cn=phony issuer,o=phony industries'
+        cmd = crud_subca.make_update_command(
+            updates=dict(addattr=bogus_issuer)
+        )
+
+        with pytest.raises(errors.ValidationError) as error:
+            cmd()
+
+        assert self.ATTR_ERROR_MSG in str(error.value)
+
+    def test_create_subca_with_conflicting_name(self, crud_subca):
+        crud_subca.ensure_exists()
+
+        cmd = crud_subca.make_create_command()
+        with pytest.raises(errors.DuplicateEntry):
+            cmd()
+
+    @pytest.mark.xfail(reason='https://fedorahosted.org/freeipa/ticket/5981',
+                       strict=True)
+    def test_create_subca_with_subject_conflict(
+            self, crud_subca, subject_conflict_subca):
+        crud_subca.ensure_exists()
+
+        with pytest.raises(errors.DuplicateEntry):
+            subject_conflict_subca.create()
diff --git a/ipatests/test_xmlrpc/tracker/ca_plugin.py b/ipatests/test_xmlrpc/tracker/ca_plugin.py
new file mode 100644
index 0000000000000000000000000000000000000000..7586c771c028df9343bcf7fcdd538c19c494ed1a
--- /dev/null
+++ b/ipatests/test_xmlrpc/tracker/ca_plugin.py
@@ -0,0 +1,126 @@
+#
+# Copyright (C) 2016  FreeIPA Contributors see COPYING for license
+#
+from __future__ import absolute_import
+
+import six
+
+from ipapython.dn import DN
+from ipatests.test_xmlrpc.tracker.base import Tracker
+from ipatests.util import assert_deepequal
+from ipatests.test_xmlrpc.xmlrpc_test import fuzzy_issuer, fuzzy_caid
+from ipatests.test_xmlrpc import objectclasses
+
+
+if six.PY3:
+    unicode = str
+
+
+class CATracker(Tracker):
+    """Implementation of a Tracker class for CA plugin."""
+
+    retrieve_keys = {
+        'dn', 'cn', 'ipacaid', 'ipacasubjectdn', 'ipacaissuerdn', 'description'
+    }
+    retrieve_all_keys = {'objectclass'} | retrieve_keys
+    create_keys = retrieve_all_keys
+    update_keys = retrieve_keys - {'dn'}
+
+    def __init__(self, name, subject, desc=u"Test generated CA",
+                 default_version=None):
+        super(CATracker, self).__init__(default_version=default_version)
+        self.attrs = {}
+        self.ipasubjectdn = subject
+        self.description = desc
+
+        self.dn = DN(('cn', name),
+                     self.api.env.container_ca,
+                     self.api.env.basedn)
+
+    def make_create_command(self, force=True):
+        """Make function that creates the plugin entry object."""
+        return self.make_command(
+            'ca_add', self.name, ipacasubjectdn=self.ipasubjectdn,
+            description=self.description
+        )
+
+    def check_create(self, result):
+        assert_deepequal(dict(
+            value=self.name,
+            summary=u'Created CA "{}"'.format(self.name),
+            result=dict(self.filter_attrs(self.create_keys))
+        ), result)
+
+    def track_create(self):
+        self.attrs = dict(
+            dn=unicode(self.dn),
+            cn=[self.name],
+            description=[self.description],
+            ipacasubjectdn=[self.ipasubjectdn],
+            ipacaissuerdn=[fuzzy_issuer],
+            ipacaid=[fuzzy_caid],
+            objectclass=objectclasses.ca
+        )
+        self.exists = True
+
+    def make_delete_command(self):
+        """Make function that deletes the plugin entry object."""
+        return self.make_command('ca_del', self.name)
+
+    def check_delete(self, result):
+        assert_deepequal(dict(
+            value=[self.name],
+            summary=u'Deleted CA "{}"'.format(self.name),
+            result=dict(failed=[])
+        ), result)
+
+    def make_retrieve_command(self, all=False, raw=False):
+        """Make function that retrieves the entry using ${CMD}_show"""
+        return self.make_command('ca_show', self.name, all=all, raw=raw)
+
+    def check_retrieve(self, result, all=False, raw=False):
+        """Check the plugin's `show` command result"""
+        if all:
+            expected = self.filter_attrs(self.retrieve_all_keys)
+        else:
+            expected = self.filter_attrs(self.retrieve_keys)
+
+        assert_deepequal(dict(
+            value=self.name,
+            summary=None,
+            result=expected
+        ), result)
+
+    def make_find_command(self, *args, **kwargs):
+        """Make function that finds the entry using ${CMD}_find
+
+        Note that the name (or other search terms) needs to be specified
+        in arguments.
+        """
+        return self.make_command('ca_find', *args, **kwargs)
+
+    def check_find(self, result, all=False, raw=False):
+        """Check the plugin's `find` command result"""
+        if all:
+            expected = self.filter_attrs(self.retrieve_all_keys)
+        else:
+            expected = self.filter_attrs(self.retrieve_keys)
+
+        assert_deepequal(dict(
+            count=1,
+            truncated=False,
+            summary=u'1 CA matched',
+            result=[expected]
+        ), result)
+
+    def make_update_command(self, updates):
+        """Make function that modifies the entry using ${CMD}_mod"""
+        return self.make_command('ca_mod', self.name, **updates)
+
+    def check_update(self, result, extra_keys=()):
+        """Check the plugin's `find` command result"""
+        assert_deepequal(dict(
+            value=self.name,
+            summary=u'Modified CA "{}"'.format(self.name),
+            result=self.filter_attrs(self.update_keys | set(extra_keys))
+        ), result)
diff --git a/ipatests/test_xmlrpc/xmlrpc_test.py b/ipatests/test_xmlrpc/xmlrpc_test.py
index c3bba9abf1079469126d4423425a32c74f886895..ddfe9c17c5ca110bc5eb66dead618383b861eda9 100644
--- a/ipatests/test_xmlrpc/xmlrpc_test.py
+++ b/ipatests/test_xmlrpc/xmlrpc_test.py
@@ -81,6 +81,9 @@ fuzzy_caacldn = Fuzzy(
     '(?i)ipauniqueid=%s,cn=caacls,cn=ca,%s' % (uuid_re, api.env.basedn)
 )
 
+# Matches internal CA ID
+fuzzy_caid = fuzzy_uuid
+
 # Matches fuzzy ipaUniqueID DN group (RDN)
 fuzzy_ipauniqueid = Fuzzy('(?i)ipauniqueid=%s' % uuid_re)
 
-- 
2.9.0

From e81e5074c439071019fb12627ff8f0945ba2f9d1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Milan=20Kub=C3=ADk?= <mku...@redhat.com>
Date: Tue, 21 Jun 2016 13:45:54 +0200
Subject: [PATCH 2/3] ipatests: Extend CAACL suite to cover Sub CA members

https://fedorahosted.org/freeipa/ticket/4559
---
 ipatests/test_xmlrpc/test_caacl_plugin.py    | 26 ++++++++++++++++++++++++--
 ipatests/test_xmlrpc/tracker/caacl_plugin.py | 26 +++++++++++++++++++++-----
 2 files changed, 45 insertions(+), 7 deletions(-)

diff --git a/ipatests/test_xmlrpc/test_caacl_plugin.py b/ipatests/test_xmlrpc/test_caacl_plugin.py
index f20b02b295024313008be7b75bdcae2ade70b4ff..dce12e484e4fa3a57fcd54fd9ffb60419fd161a4 100644
--- a/ipatests/test_xmlrpc/test_caacl_plugin.py
+++ b/ipatests/test_xmlrpc/test_caacl_plugin.py
@@ -14,6 +14,7 @@ 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.stageuser_plugin import StageUserTracker
+from ipatests.test_xmlrpc.tracker.ca_plugin import CATracker
 
 
 @pytest.fixture(scope='class')
@@ -48,12 +49,19 @@ def category_acl(request):
     name = u'category_acl'
     tracker = CAACLTracker(name, ipacertprofile_category=u'all',
                            user_category=u'all', service_category=u'all',
-                           host_category=u'all')
+                           host_category=u'all', ipaca_category=u'all')
 
     return tracker.make_fixture(request)
 
 
 @pytest.fixture(scope='class')
+def caacl_test_ca(request):
+    name = u'caacl-test-ca'
+    subject = u'CN=caacl test subca,O=test industries inc.'
+    return CATracker(name, subject).make_fixture(request)
+
+
+@pytest.fixture(scope='class')
 def staged_user(request):
     name = u'st-user'
     tracker = StageUserTracker(name, u'stage', u'test')
@@ -109,7 +117,8 @@ class TestCAACLMembers(XMLRPC_test):
             hostcategory=None,
             servicecategory=None,
             ipacertprofilecategory=None,
-            usercategory=None)
+            usercategory=None,
+            ipacacategory=None)
         category_acl.update(updates)
 
     def test_add_profile(self, category_acl, default_profile):
@@ -120,6 +129,15 @@ class TestCAACLMembers(XMLRPC_test):
         category_acl.remove_profile(certprofile=default_profile.name)
         category_acl.retrieve()
 
+    def test_add_ca(self, category_acl, caacl_test_ca):
+        caacl_test_ca.ensure_exists()
+        category_acl.add_ca(ca=caacl_test_ca.name)
+        category_acl.retrieve()
+
+    def test_remove_ca(self, category_acl, caacl_test_ca):
+        category_acl.remove_ca(ca=caacl_test_ca.name)
+        category_acl.retrieve()
+
     def test_add_invalid_value_service(self, category_acl, default_profile):
         res = category_acl.add_service(service=default_profile.name, track=False)
         assert len(res['failed']) == 1
@@ -144,6 +162,10 @@ class TestCAACLMembers(XMLRPC_test):
         res = category_acl.add_profile(certprofile=category_acl.name, track=False)
         assert len(res['failed']) == 1
 
+    def test_add_invalid_value_ca(self, category_acl):
+        res = category_acl.add_ca(ca=category_acl.name, track=False)
+        assert len(res['failed']) == 1
+
     def test_add_staged_user_to_acl(self, category_acl, staged_user):
         res = category_acl.add_user(user=staged_user.name, track=False)
         assert len(res['failed']) == 1
diff --git a/ipatests/test_xmlrpc/tracker/caacl_plugin.py b/ipatests/test_xmlrpc/tracker/caacl_plugin.py
index afe7ee0c071b6346d9a21337d8e486ff8b2891cc..79c892d27e88b3b263915cc0bf843a1235b4836e 100644
--- a/ipatests/test_xmlrpc/tracker/caacl_plugin.py
+++ b/ipatests/test_xmlrpc/tracker/caacl_plugin.py
@@ -35,10 +35,11 @@ class CAACLTracker(Tracker):
         u'memberuser_user', u'memberuser_group',
         u'memberhost_host', u'memberhost_hostgroup',
         u'memberservice_service',
-        u'ipamembercertprofile_certprofile'}
+        u'ipamembercertprofile_certprofile',
+        u'ipamemberca_ca'}
     category_keys = {
         u'ipacacategory', u'ipacertprofilecategory', u'usercategory',
-        u'hostcategory', u'servicecategory'}
+        u'hostcategory', u'servicecategory', u'ipacacategory'}
     retrieve_keys = {
         u'dn', u'cn', u'description', u'ipaenabledflag',
         u'ipamemberca', u'ipamembercertprofile', u'memberuser',
@@ -51,14 +52,15 @@ class CAACLTracker(Tracker):
     update_keys = create_keys - {u'dn'}
 
     def __init__(self, name, ipacertprofile_category=None, user_category=None,
-                 service_category=None, host_category=None, description=None,
-                 default_version=None):
+                 service_category=None, host_category=None,
+                 ipaca_category=None, description=None, default_version=None):
         super(CAACLTracker, self).__init__(default_version=default_version)
 
         self._name = name
         self.description = description
         self._categories = dict(
             ipacertprofilecategory=ipacertprofile_category,
+            ipacacategory=ipaca_category,
             usercategory=user_category,
             servicecategory=service_category,
             hostcategory=host_category)
@@ -200,7 +202,7 @@ class CAACLTracker(Tracker):
     # implemented in standalone test
     #
     # The methods implemented here will be:
-    # caacl_{add,remove}_{host, service, certprofile, user [, subca]}
+    # caacl_{add,remove}_{host, service, certprofile, user, ca}
 
     def _add_acl_component(self, command_name, keys, track):
         """ Add a resource into ACL rule and track it.
@@ -356,6 +358,20 @@ class CAACLTracker(Tracker):
 
         return self._remove_acl_component(u'caacl_remove_profile', options, track)
 
+    def add_ca(self, ca=None, track=True):
+        options = {
+            u'ipamemberca_ca':
+                {u'ca': ca}}
+
+        return self._add_acl_component(u'caacl_add_ca', options, track)
+
+    def remove_ca(self, ca=None, track=True):
+        options = {
+            u'ipamemberca_ca':
+                {u'ca': ca}}
+
+        return self._remove_acl_component(u'caacl_remove_ca', options, track)
+
     def enable(self):
         command = self.make_command(u'caacl_enable', self.name)
         self.attrs.update({u'ipaenabledflag': [u'TRUE']})
-- 
2.9.0

From b3e43108f1822fd83c602a7eecec933889531d1b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Milan=20Kub=C3=ADk?= <mku...@redhat.com>
Date: Tue, 21 Jun 2016 15:57:58 +0200
Subject: [PATCH 3/3] ipatests: Test Sub CA with CAACL and certificate profile

Test the Sub CA feature by signing a CSR with custom
certificate profile.

The test also covers 'cert-request' fallback behaviour
for missing 'cacn' and 'profile-id' options by reusing
the fixtures from the module.

https://fedorahosted.org/freeipa/ticket/4559
---
 .../test_xmlrpc/test_caacl_profile_enforcement.py  | 110 +++++++++++++++++++++
 1 file changed, 110 insertions(+)

diff --git a/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py b/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py
index 11c040966003e2ea86149359c8aacb953e9fdd37..a70d81d885cdf0b4c8bbbdaa7d6f69bfbd84719c 100644
--- a/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py
+++ b/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py
@@ -15,6 +15,7 @@ from ipatests.util import (
 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 ipapython.ipautil import run
 
@@ -250,3 +251,112 @@ class TestSignWithChangedProfile(XMLRPC_test):
             with pytest.raises(errors.CertificateOperationError):
                 api.Command.cert_request(csr, principal=smime_user,
                                          profile_id=smime_profile.name)
+
+
+@pytest.fixture(scope='class')
+def smime_signing_ca(request):
+    name = u'smime-signing-ca'
+    subject = u'CN=SMIME CA,O=test industries Inc.'
+    return CATracker(name, subject).make_fixture(request)
+
+
+@pytest.mark.tier1
+class TestCertSignMIMEwithSubCA(XMLRPC_test):
+    """ Test Certificate Signing with Sub CA
+
+    The test covers following areas:
+
+     * signing a CSR with custom certificate profile
+       using a designated Sub CA
+     * Verify that the Issuer of the signed certificate
+       is the reqested CA
+     * Verify that when not set, cert-request uses the default CA.
+       This it verified by violating an ACL
+     * Verify that when not set, cert-request uses the default
+       certificate profile.
+
+    The latter two test cases are implemented in this module
+    as not to replicate the fixtures to cert plugin test module.
+    """
+
+    def test_cert_import(self, smime_profile):
+        smime_profile.ensure_exists()
+
+    def test_create_acl(self, smime_acl):
+        smime_acl.ensure_exists()
+
+    def test_create_subca(self, smime_signing_ca):
+        smime_signing_ca.ensure_exists()
+
+    def test_add_profile_to_acl(self, smime_acl, smime_profile):
+        smime_acl.add_profile(certprofile=smime_profile.name)
+
+    def test_add_subca_to_acl(self, smime_acl, smime_signing_ca):
+        smime_acl.add_ca(smime_signing_ca.name)
+
+    # rewrite to trackers, prepare elsewhere
+    def test_add_user_to_group(self, smime_group, smime_user):
+        api.Command.group_add_member(smime_group, user=smime_user)
+
+    def test_add_group_to_acl(self, smime_group, smime_acl):
+        smime_acl.add_user(group=smime_group)
+
+    def test_sign_smime_csr(self, smime_profile, smime_user, smime_signing_ca):
+        csr = generate_user_csr(smime_user)
+        with change_principal(smime_user, SMIME_USER_PW):
+            api.Command.cert_request(csr, principal=smime_user,
+                                     profile_id=smime_profile.name,
+                                     cacn=smime_signing_ca.name)
+
+    def test_sign_smime_csr_full_principal(
+            self, smime_profile, smime_user, smime_signing_ca):
+        csr = generate_user_csr(smime_user)
+        smime_user_principal = '@'.join((smime_user, api.env.realm))
+        with change_principal(smime_user, SMIME_USER_PW):
+            api.Command.cert_request(csr, principal=smime_user_principal,
+                                     profile_id=smime_profile.name,
+                                     cacn=smime_signing_ca.name)
+
+    def test_verify_cert_issuer_dn_is_subca(
+            self, smime_profile, smime_user, smime_signing_ca):
+        csr = generate_user_csr(smime_user)
+        smime_user_principal = '@'.join((smime_user, api.env.realm))
+        with change_principal(smime_user, SMIME_USER_PW):
+            cert_info = api.Command.cert_request(
+                csr, principal=smime_user_principal,
+                profile_id=smime_profile.name, cacn=smime_signing_ca.name)
+
+        assert cert_info['result']['issuer'] == smime_signing_ca.ipasubjectdn
+
+    def test_sign_smime_csr_fallback_to_default_CA(
+            self, smime_profile, smime_user, smime_signing_ca):
+        """ Attempt to sign a CSR without CA specified.
+
+        The request will satisfy SMIME_ACL via the profile ID,
+        however not specifying the CA will fallback to the IPA CA
+        for which SMIME profile isn't enabled, thus violating ACL.
+        """
+        csr = generate_user_csr(smime_user)
+        smime_user_principal = '@'.join((smime_user, api.env.realm))
+
+        with pytest.raises(errors.ACIError):
+            with change_principal(smime_user, SMIME_USER_PW):
+                api.Command.cert_request(csr, principal=smime_user_principal,
+                                         profile_id=smime_profile.name)
+
+    def test_sign_smime_csr_fallback_to_default_cert_profile(
+            self, smime_profile, smime_user, smime_signing_ca):
+        """ Attempt to sign a CSR without certificate profile specified.
+
+        Similar to previous test case.
+        By specifying only the CA to use, profile will fallback to
+        the default caIPAserviceCert profile which is not enabled
+        via ACL to be used with the CA, thus failing the request.
+        """
+        csr = generate_user_csr(smime_user)
+        smime_user_principal = '@'.join((smime_user, api.env.realm))
+
+        with pytest.raises(errors.ACIError):
+            with change_principal(smime_user, SMIME_USER_PW):
+                api.Command.cert_request(csr, principal=smime_user_principal,
+                                         cacn=smime_signing_ca.name)
-- 
2.9.0

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to