Hi list,

before my PTO, I was trying to write a functional test for CA ACLs with the tracker along all other acceptance/functional tests.

I wasn't successful, the approach doesn't seem to work for CA ACLs as they have specific requirements for kerberos credentials that none of my attempts were able to met. I have tried several approaches and the memo I got out of this is that currently, there seems to be no way how to conveniently run a test that changes the user identity during the functional test (xmlrpc tests).

I haven't had much time to write an integration test that should solve these problems with changing identity.

The approaches I have tried include, in no particular order:

* switch the default ccache to the identity desired, before calls made on an API object
    - in case of FILE ccache, moving it back and forth
    - in case of kernel keyring, using kswitch

* instantiating another API instance in the process running the test, while the other ccache is active - the API object internals seem to prevent this as there is still a lot of shared state between the API instances

* running the command supposed to have different identity as a subprocess after switching the identity - this attempt seemed to have inherited the opened connection to the backend from the parent python process,
      creating a conflict during the client bootstrap

* injecting the KRB5CCNAME environment variable with second identity into the python process - the API instance doesn't seem to be affected by this value half of the times.
    - randomly, the new credentials are used, breaking all the things.

Unable to change the user during the test, the code I wrote for this wasn't doing what I intended it to do
because the admin user used in the tests overrides all CA ACLs.

The patches implement the CA ACL tracker and, at the moment, one simple test. This can (and will) be extended to full CRUD test that will be run as a part of the acceptance suite, while functional test will be written as an integration test.

I include the code that doesn't work as an example of what will be in the integration test.

The patch 0013 needs to be applied after the certprofile tracker patch (0008).

Cheers,
Milan
From 894c3692bf96d3ddf0431cadb86dea8c39b610a8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Milan=20Kub=C3=ADk?= <mku...@redhat.com>
Date: Fri, 17 Jul 2015 14:42:23 +0200
Subject: [PATCH 3/5] ipatests: add fuzzy instances for CA ACL DN and RDN

---
 ipatests/test_xmlrpc/xmlrpc_test.py | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/ipatests/test_xmlrpc/xmlrpc_test.py b/ipatests/test_xmlrpc/xmlrpc_test.py
index 56ddad9b8a0a1164c29f38970e0a97513d1a8d1f..c8be6160bdca0a95622ce5f8e4752e609f73dec5 100644
--- a/ipatests/test_xmlrpc/xmlrpc_test.py
+++ b/ipatests/test_xmlrpc/xmlrpc_test.py
@@ -77,6 +77,14 @@ fuzzy_sudocmddn = Fuzzy(
     '(?i)ipauniqueid=%s,cn=sudocmds,cn=sudo,%s' % (uuid_re, api.env.basedn)
 )
 
+# Matches caacl dn
+fuzzy_caacldn = Fuzzy(
+    '(?i)ipauniqueid=%s,cn=caacls,cn=ca,%s' % (uuid_re, api.env.basedn)
+)
+
+# Matches fuzzy ipaUniqueID DN group (RDN)
+fuzzy_ipauniqueid = Fuzzy('(?i)ipauniqueid=%s' % uuid_re)
+
 # Matches a hash signature, not enforcing length
 fuzzy_hash = Fuzzy('^([a-f0-9][a-f0-9]:)+[a-f0-9][a-f0-9]$', type=six.string_types)
 
-- 
2.5.1

From a2eef3966d297c1e90327f994de8ee47b8e30fd2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Milan=20Kub=C3=ADk?= <mku...@redhat.com>
Date: Tue, 30 Jun 2015 17:00:18 +0200
Subject: [PATCH 4/5] ipatests: Add initial CAACLTracker implementation

The patch implements the tracker for CA ACL feature.
The basic CRUD checkers has been implemented. The methods
for adding and removing the association of the resources
with the ACL do not have the check methods. These will be provided
as a separate test suite.
---
 ipatests/test_xmlrpc/objectclasses.py     |   5 +
 ipatests/test_xmlrpc/test_caacl_plugin.py | 318 ++++++++++++++++++++++++++++++
 2 files changed, 323 insertions(+)
 create mode 100644 ipatests/test_xmlrpc/test_caacl_plugin.py

diff --git a/ipatests/test_xmlrpc/objectclasses.py b/ipatests/test_xmlrpc/objectclasses.py
index 1cd77c7f885fe408d0d9d48fc6d8284900c91b7f..134a08803f3abca1124c4d26274d9e3fc981b941 100644
--- a/ipatests/test_xmlrpc/objectclasses.py
+++ b/ipatests/test_xmlrpc/objectclasses.py
@@ -217,3 +217,8 @@ certprofile = [
     u'top',
     u'ipacertprofile',
 ]
+
+caacl = [
+    u'ipaassociation',
+    u'ipacaacl'
+]
diff --git a/ipatests/test_xmlrpc/test_caacl_plugin.py b/ipatests/test_xmlrpc/test_caacl_plugin.py
new file mode 100644
index 0000000000000000000000000000000000000000..ba3408813d5d47f7f6261f187129fbee645c5ef7
--- /dev/null
+++ b/ipatests/test_xmlrpc/test_caacl_plugin.py
@@ -0,0 +1,318 @@
+#
+# Copyright (C) 2015  FreeIPA Contributors see COPYING for license
+#
+
+"""
+Test the `ipalib.plugins.caacl` module.
+"""
+
+import os
+
+import pytest
+
+from ipapython import ipautil
+from ipalib import errors, x509
+from ipapython.dn import DN
+from ipatests.test_xmlrpc.ldaptracker import Tracker
+from ipatests.test_xmlrpc.xmlrpc_test import (XMLRPC_test, fuzzy_caacldn,
+                                              fuzzy_uuid, fuzzy_ipauniqueid,
+                                              raises_exact)
+from ipatests.test_xmlrpc import objectclasses
+from ipatests.util import assert_deepequal
+
+
+class CAACLTracker(Tracker):
+    """Tracker class for CA ACL LDAP object."""
+    # TODO: more documentation for this class
+    # TODO: find a way how to restore the ACL
+    #       after delete. Simple `ensure_exists`
+    #       won't be enough here as the services,
+    #       hosts, etc. are added after the ACL
+    #       itself is created.
+
+    member_keys = {
+        u'memberuser_user', u'memberuser_group',
+        u'memberhost_host', u'memberhost_hostgroup',
+        u'memberservice_service',
+        u'ipamembercertprofile_certprofile'}
+    retrieve_keys = {
+        u'dn', u'cn', u'description', u'ipaenabledflag',
+        u'ipacacategory', u'ipamemberca',
+        u'ipacertprofilecategory', u'ipamembercertprofile',
+        u'usercategory', u'memberuser',
+        u'hostcategory', u'memberhost',
+        u'servicecategory', u'memberservice'} | member_keys
+    retrieve_all_keys = retrieve_keys | {u'objectclass', u'ipauniqueid'}
+    create_keys = {u'dn', u'cn', u'description', u'ipacertprofilecategory',
+                   u'usercategory', u'hostcategory', u'ipacacategory',
+                   u'ipaenabledflag', u'objectclass', u'ipauniqueid'}
+    update_keys = create_keys - {u'dn'}
+
+    def __init__(self, name, profile_category=None, user_category=None,
+                 service_category=None, host_category=None, description=None,
+                 default_version=None):
+        super(CAACLTracker, self).__init__(default_version=default_version)
+
+        self._name = name
+        self.description = description
+        self._categories = dict(
+            profilecategory=[profile_category],
+            usercategory=[user_category],
+            servicecategory=[service_category],
+            hostcategory=[host_category])
+
+        self.dn = fuzzy_caacldn
+
+    @property
+    def name(self):
+        return self._name
+
+    @property
+    def rdn(self):
+        return fuzzy_ipauniqueid
+
+    @property
+    def categories(self):
+        return self._categories
+
+    @property
+    def create_categories(self):
+        """Return the categories set on create."""
+        return dict(filter(lambda x: x[1][0], self.categories.items()))
+
+    def make_create_command(self, force=True):
+        return self.make_command(u'caacl_add', self.name,
+                                 description=self.description,
+                                 **self.create_categories)
+
+    def check_create(self, result):
+        assert_deepequal(dict(
+            value=self.name,
+            summary=u'Added CA ACL "{}"'.format(self.name),
+            result=dict(self.filter_attrs(self.create_keys))
+        ), result)
+
+    def track_create(self):
+        self.attrs = dict(
+            dn=self.dn,
+            ipauniqueid=[fuzzy_uuid],
+            cn=[self.name],
+            objectclass=objectclasses.caacl,
+            ipaenabledflag=[u'TRUE'])
+
+        self.attrs.update(self.create_categories)
+        if self.description:
+            self.attrs.update({u'description', [self.description]})
+
+        self.exists = True
+
+    def make_delete_command(self):
+        return self.make_command('caacl_del', self.name)
+
+    def check_delete(self, result):
+        assert_deepequal(dict(
+            value=[self.name],
+            summary=u'Deleted CA ACL "{}"'.format(self.name),
+            result=dict(failed=[])
+        ), result)
+
+    def make_retrieve_command(self, all=False, raw=False):
+        return self.make_command('caacl_show', self.name, all=all, raw=raw)
+
+    def check_retrieve(self, result, all=False, raw=False):
+        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):
+        return self.make_command('caacl_find', *args, **kwargs)
+
+    def check_find(self, result, all=False, raw=False):
+        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 ACL matched',
+            result=[expected]
+        ), result)
+
+    def make_update_command(self, updates):
+        return self.make_command('caacl_mod', self.name, **updates)
+
+    def check_update(self, result, extra_keys=()):
+        assert_deepequal(dict(
+            value=self.name,
+            summary=u'Modified CA ACL "{}"'.format(self.name),
+            result=self.filter_attrs(self.update_keys | set(extra_keys))
+        ), result)
+
+    # Helper methods for caacl subcommands. The check methods will be
+    # implemented in standalone test
+    #
+    # The methods implemented here will be:
+    # caacl_{add,remove}_{host, service, certprofile, user [, subca]}
+
+    # TODO: can API command take single value as unicode or
+    #       do we need a list with one element?
+    def _add_acl_component(self, command_name, keys):
+        """ Add a resource into ACL rule and track it.
+
+            command_name - the name in the API
+            keys = {
+                'tracker_attr': {
+                    'api_key': 'value'
+                }
+            }
+
+            e.g.
+
+            keys = {
+                'memberhost_host': {
+                    'host': 'hostname'
+                },
+                'memberhost_hostgroup': {
+                    'hostgroup': 'hostgroup_name'
+                }
+            }
+        """
+
+        if not self.exists:
+            raise errors.NotFound(reason="The tracked entry doesn't exist.")
+
+        command = self.make_command(command_name, self.name)
+        command_options = dict()
+
+        # track
+        for tracker_attr in keys:
+            api_options = keys[tracker_attr]
+            for option in api_options:
+                try:
+                    self.attrs[tracker_attr].append(api_options[option])
+                except KeyError:
+                    self.attrs[tracker_attr] = [api_options[option]]
+            # prepare options for the command call
+            command_options.update(api_options)
+
+        return command(**command_options)
+
+    def _remove_acl_component(self, command_name, keys):
+        """ Remove a resource from ACL rule and track it.
+
+            command_name - the name in the API
+            keys = {
+                'tracker_attr': {
+                    'api_key': 'value'
+                }
+            }
+
+            e.g.
+
+            keys = {
+                'memberhost_host': {
+                    'host': 'hostname'
+                },
+                'memberhost_hostgroup': {
+                    'hostgroup': 'hostgroup_name'
+                }
+            }
+        """
+        command = self.make_command(command_name, self.name)
+        command_options = dict()
+
+        for tracker_attr in keys:
+            api_options = keys[tracker_attr]
+            for option in api_options:
+                self.attrs[tracker_attr].remove(api_options[option])
+                if len(self.attrs[tracker_attr]) == 0:
+                    del self.attrs[tracker_attr]
+            command_options.update(api_options)
+
+        return command(**command_options)
+
+    def add_host(self, host=None, hostgroup=None):
+        """Associates an host or hostgroup entry with the ACL.
+
+           The command takes an unicode string with the name
+           of the entry (RDN).
+
+           It is the responsibility of a test writer to provide
+           the correct value, object type as the method does not
+           verify whether the entry exists.
+
+           The method can add only one entry of each type
+           in one call.
+        """
+
+        options = {
+            u'memberhost_host': {u'host': host},
+            u'memberhost_hostgroup': {u'hostgroup': hostgroup}}
+
+        return self._add_acl_component(u'caacl_add_host', options)
+
+    def remove_host(self, host=None, hostgroup=None):
+        options = {
+            u'memberhost_host': {u'host': host},
+            u'memberhost_hostgroup': {u'hostgroup': hostgroup}}
+
+        return self._remove_acl_component(u'caacl_remove_host', options)
+
+    def add_user(self, user=None, group=None):
+        options = {
+            u'memberuser_user': {u'user': user},
+            u'memberuser_group': {u'group': group}}
+
+        return self._add_acl_component(u'caacl_add_user', options)
+
+    def remove_user(self, user=None, group=None):
+        options = {
+            u'memberuser_user': {u'user': user},
+            u'memberuser_group': {u'group': group}}
+
+        return self._remove_acl_component(u'caacl_remove_user', options)
+
+    def add_service(self, service=None):
+        options = {
+            u'memberservice_service': {u'service': service}}
+
+        return self._add_acl_component(u'caacl_add_service', options)
+
+    def remove_service(self, service=None):
+        options = {
+            u'memberservice_service': {u'service': service}}
+
+        self._remove_acl_component(u'caacl_remove_service', options)
+
+    def add_profile(self, certprofile=None):
+        options = {
+            u'ipamembercertprofile_certprofile':
+                {u'certprofile': certprofile}}
+
+        self._add_acl_component(u'caacl_add_profile', options)
+
+    def remove_profile(self, certprofile=None):
+        options = {
+            u'ipamembercertprofile_certprofile':
+                {u'certprofile': certprofile}}
+
+        self._remove_acl_component(u'caacl_remove_profile', options)
+
+    def enable(self):
+        command = self.make_command(u'caacl_enable', self.name)
+        self.attrs.update({u'ipaenabledflag': u'TRUE'})
+        command()
+
+    def disable(self):
+        command = self.make_command(u'caacl_disable', self.name)
+        self.attrs.update({u'ipaenabledflag': u'FALSE'})
+        command()
-- 
2.5.1

From 00d209de3f06b12bbfe0e63321632b57c3622ff9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Milan=20Kub=C3=ADk?= <mku...@redhat.com>
Date: Fri, 7 Aug 2015 15:54:18 +0200
Subject: [PATCH 5/5] tests: add test to check the default ACL

---
 ipatests/test_xmlrpc/test_caacl_plugin.py | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/ipatests/test_xmlrpc/test_caacl_plugin.py b/ipatests/test_xmlrpc/test_caacl_plugin.py
index ba3408813d5d47f7f6261f187129fbee645c5ef7..0d5658f1b5398a93ccf96092ec1ea15a2bd68813 100644
--- a/ipatests/test_xmlrpc/test_caacl_plugin.py
+++ b/ipatests/test_xmlrpc/test_caacl_plugin.py
@@ -316,3 +316,18 @@ class CAACLTracker(Tracker):
         command = self.make_command(u'caacl_disable', self.name)
         self.attrs.update({u'ipaenabledflag': u'FALSE'})
         command()
+
+
+@pytest.fixture(scope='class')
+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
+
+
+class TestDefaultACL(XMLRPC_test):
+    def test_default_acl_present(self, default_acl):
+        default_acl.retrieve()
-- 
2.5.1

From f280822ee4b6d5b1e446907fcd186ae9acdcce71 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Milan=20Kub=C3=ADk?= <mku...@redhat.com>
Date: Sun, 23 Aug 2015 01:17:24 +0200
Subject: [PATCH] ipatests: CA ACL and cert profile functional test

---
 .../test_xmlrpc/test_caacl_profile_enforcement.py  | 234 +++++++++++++++++++++
 1 file changed, 234 insertions(+)
 create mode 100644 ipatests/test_xmlrpc/test_caacl_profile_enforcement.py

diff --git a/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py b/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py
new file mode 100644
index 0000000000000000000000000000000000000000..a698ea01da0799dcacfe9616a6d4e3dc444db042
--- /dev/null
+++ b/ipatests/test_xmlrpc/test_caacl_profile_enforcement.py
@@ -0,0 +1,234 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015  FreeIPA Contributors see COPYING for license
+#
+
+import os
+import py
+import pytest
+
+import subprocess
+
+from ipalib import api, errors
+from ipatests.test_xmlrpc.utils import unlock_principal_password
+from ipatests.test_xmlrpc.xmlrpc_test import XMLRPC_test
+from ipatests.test_xmlrpc.test_certprofile_plugin import CertprofileTracker
+from ipatests.test_xmlrpc.test_caacl_plugin import CAACLTracker
+
+
+BASE_DIR = os.path.dirname(__file__)
+
+SMIME_PROFILE_TEMPLATE = os.path.join(BASE_DIR, 'data/smime.cfg.tmpl')
+ALICE_OPENSSL_CONFIG_TEMPLATE = os.path.join(BASE_DIR, 'data/alice.conf.tmpl')
+ALICE_RSA_PRIVATE_KEY_PATH = os.path.join(BASE_DIR, 'data/alice-key.pem')
+
+CERT_SUBJECT_BASE = (
+    api.Command.config_show()
+    ['result']['ipacertificatesubjectbase'][0]
+)
+
+
+# environment preparation
+
+
+def _prepare_config(template, values):
+    tmpdir = py.path.local('/tmp').mkdtemp()
+    config = tmpdir.join('expanded.conf')
+
+    with open(template) as f:
+        template = f.read()
+
+    with open(unicode(config), 'w') as f:
+        f.write(template.format(**values))
+
+    return unicode(config.realpath())
+
+
+def _call_openssl(key, config_template, template_values):
+    csr_file = py.path.local('/tmp').mkdtemp().join('cert-request.pem')
+
+    subprocess.call(['openssl', 'req',
+                     '-new',
+                     '-key', key,
+                     '-out', unicode(csr_file),
+                     '-config', _prepare_config(
+                        config_template,
+                        template_values)])
+
+    return csr_file
+
+
+@pytest.fixture(scope='class')
+def correct_csr(request):
+    csr_path = _call_openssl(
+        ALICE_RSA_PRIVATE_KEY_PATH,
+        ALICE_OPENSSL_CONFIG_TEMPLATE,
+        dict(
+            ipacertbase=CERT_SUBJECT_BASE,
+            ipadomain=api.env.domain))
+
+    def fin():
+        csr_path.remove()
+    request.addfinalizer(fin)
+
+    return unicode(csr_path.read())
+
+
+@pytest.fixture(scope='class')
+def smime_profile(request):
+    profile_path = _prepare_config(
+            SMIME_PROFILE_TEMPLATE,
+            dict(ipadomain=api.env.domain, iparealm=api.env.realm))
+
+    tracker = CertprofileTracker(u'smime', store=True,
+                                 desc=u"S/MIME certificate profile",
+                                 profile=profile_path)
+
+    # return tracker
+    return tracker.make_fixture(request)
+
+
+@pytest.fixture(scope='class')
+def smime_acl(request):
+    tracker = CAACLTracker(u'smime_acl')
+
+    # return tracker
+    return tracker.make_fixture(request)
+
+
+# TODO: rewrite these into Tracker instances
+@pytest.fixture(scope='class')
+def smime_user(request):
+    api.Command.user_add(uid=u'alice', givenname=u'Alice', sn=u'SMIME',
+                         userpassword=u'Change123')
+
+    unlock_principal_password('alice', 'Change123', 'Secret123')
+
+    def fin():
+        api.Command.user_del(u'alice')
+    request.addfinalizer(fin)
+
+    return u'alice'
+
+
+@pytest.fixture(scope='class')
+def smime_group(request):
+    api.Command.group_add(u'smime_users')
+
+    def fin():
+        api.Command.group_del(u'smime_users')
+    request.addfinalizer(fin)
+
+    return u'smime_users'
+
+
+# Fixtures to use with `change_principal` fixture
+@pytest.fixture(scope='function')
+def principal(request):
+    # use our smime_user principal
+    return u'alice'
+
+
+@pytest.fixture(scope='function')
+def password(request):
+    # provide password fow our changed principal
+    return u'Secret123'
+
+
+class TestCertSignMIME(XMLRPC_test):
+
+    def test_cert_import(self, smime_profile):
+        smime_profile.ensure_exists()
+
+    def test_create_acl(self, smime_acl):
+        smime_acl.ensure_exists()
+
+    def test_add_profile_to_acl(self, smime_acl, smime_profile):
+        smime_acl.add_profile(certprofile=smime_profile.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)
+
+    @pytest.mark.usefixtures('change_principal')
+    def test_sign_smime_csr(self, smime_profile, correct_csr, smime_user):
+        api.Command.cert_request(correct_csr, principal=smime_user,
+                                 profile_id=smime_profile.name)
+
+
+class TestSignWithDisabledACL(XMLRPC_test):
+
+    def test_import_profile_and_acl(self, smime_profile, smime_acl):
+        smime_profile.ensure_exists()
+        smime_acl.ensure_missing()
+        smime_acl.ensure_exists()
+
+    def test_add_profile_to_acl(self, smime_acl, smime_profile):
+        smime_acl.add_profile(certprofile=smime_profile.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_disable_acl(self, smime_acl):
+        smime_acl.disable()
+
+    @pytest.mark.usefixtures('change_principal')
+    def test_signing_with_disabled_acl(self, correct_csr, smime_acl,
+                                       smime_profile, smime_user):
+
+        with pytest.raises(errors.ACIError):
+            api.Command.cert_request(
+                correct_csr, profile_id=smime_profile.name,
+                principal=smime_user)
+
+    def test_admin_overrides_disabled_acl(self, correct_csr, smime_acl,
+                                          smime_profile, smime_user):
+        api.Command.cert_request(
+            correct_csr, profile_id=smime_profile.name,
+            principal=smime_user)
+
+
+class TestSignWithoutGroupMembership(XMLRPC_test):
+
+    def test_import_profile_and_acl(self, smime_profile, smime_acl):
+        smime_profile.ensure_exists()
+        smime_acl.ensure_missing()
+        smime_acl.ensure_exists()
+
+    def test_add_profile_to_acl(self, smime_acl, smime_profile):
+        smime_acl.add_profile(certprofile=smime_profile.name)
+
+    def test_add_group_to_acl(self, smime_group, smime_acl, smime_user):
+        # smime user should not be a member of this group
+        # 
+        # adding smime_user fixture to ensure it exists
+        # TODO: change user to tracker and call ensure_exists
+        smime_acl.add_user(group=smime_group)
+
+    @pytest.mark.usefixtures('change_principal')
+    def test_signing_with_non_member_principal(self, correct_csr, smime_acl,
+                                               smime_profile, smime_user):
+
+        with pytest.raises(errors.ACIError):
+            api.Command.cert_request(
+                correct_csr,
+                profile_id=smime_profile.name,
+                principal=smime_user)
+
+    def test_admin_overrides_group_membership(self, correct_csr, smime_acl,
+                                              smime_profile, smime_user):
+        api.Command.cert_request(
+            correct_csr, profile_id=smime_profile.name,
+            principal=smime_user)
+
+
+class TestSignWithChangedProfile(XMLRPC_test):
+    """ Test to verify that the updated profile is used."""
+    pass
-- 
2.5.1

-- 
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