URL: https://github.com/freeipa/freeipa/pull/399 Author: dkupka Title: #399: Certificate mapping test Action: synchronized
To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/399/head:pr399 git checkout pr399
From bdd96f302520fd9cbef19d2b2716e8c29244750d Mon Sep 17 00:00:00 2001 From: David Kupka <dku...@redhat.com> Date: Fri, 13 Jan 2017 13:17:35 +0100 Subject: [PATCH 1/3] test_xmlrpc: tracker: Add enable and disable methods to tracker Prepare tracker for easier testing of *-{en,dis}able commands. --- ipatests/test_xmlrpc/tracker/base.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/ipatests/test_xmlrpc/tracker/base.py b/ipatests/test_xmlrpc/tracker/base.py index aa88e6b..d8cd3a6 100644 --- a/ipatests/test_xmlrpc/tracker/base.py +++ b/ipatests/test_xmlrpc/tracker/base.py @@ -198,6 +198,14 @@ def make_update_command(self, updates): """Make function that modifies the entry using ${CMD}_mod""" raise NotImplementedError(self._override_me_msg) + def make_enable_command(self): + """Make function that enables the entry using ${CMD}_enable""" + raise NotImplementedError(self._override_me_msg) + + def make_disable_command(self): + """Make function that disables the entry using ${CMD}_disable""" + raise NotImplementedError(self._override_me_msg) + def create(self): """Helper function to create an entry and check the result""" self.track_create() @@ -285,3 +293,21 @@ def update(self, updates, expected_updates=None): def check_update(self, result, extra_keys=()): """Check the plugin's `mod` command result""" raise NotImplementedError(self._override_me_msg) + + def enable(self): + command = self.make_enable_command() + result = command() + self.check_enable(result) + + def check_enable(self, result): + """Check the plugin's `enable` command result""" + raise NotImplementedError(self._override_me_msg) + + def disable(self): + command = self.make_disable_command() + result = command() + self.check_disable(result) + + def check_disable(self, result): + """Check the plugin's `disable` command result""" + raise NotImplementedError(self._override_me_msg) From b6ddcc0aaa69fcf6a17829af0385433550f3c363 Mon Sep 17 00:00:00 2001 From: David Kupka <dku...@redhat.com> Date: Fri, 13 Jan 2017 13:22:45 +0100 Subject: [PATCH 2/3] test: certmap: Add basic tests for certmaprule commands. https://fedorahosted.org/freeipa/ticket/6542 --- ipatests/test_xmlrpc/objectclasses.py | 5 + ipatests/test_xmlrpc/test_certmap_plugin.py | 107 ++++++++++++++++ ipatests/test_xmlrpc/tracker/certmap_plugin.py | 167 +++++++++++++++++++++++++ 3 files changed, 279 insertions(+) create mode 100644 ipatests/test_xmlrpc/test_certmap_plugin.py create mode 100644 ipatests/test_xmlrpc/tracker/certmap_plugin.py diff --git a/ipatests/test_xmlrpc/objectclasses.py b/ipatests/test_xmlrpc/objectclasses.py index 1ea020b..0a15a21 100644 --- a/ipatests/test_xmlrpc/objectclasses.py +++ b/ipatests/test_xmlrpc/objectclasses.py @@ -227,3 +227,8 @@ u'top', u'ipaca', ] + +certmaprule = [ + u'top', + u'ipacertmaprule', +] diff --git a/ipatests/test_xmlrpc/test_certmap_plugin.py b/ipatests/test_xmlrpc/test_certmap_plugin.py new file mode 100644 index 0000000..9343f9a --- /dev/null +++ b/ipatests/test_xmlrpc/test_certmap_plugin.py @@ -0,0 +1,107 @@ +# +# Copyright (C) 2017 FreeIPA Contributors see COPYING for license +# + +import itertools +import pytest + +from ipapython.dn import DN +from ipatests.test_xmlrpc.xmlrpc_test import XMLRPC_test +from ipatests.test_xmlrpc.tracker.certmap_plugin import CertmapruleTracker + +certmaprule_create_params = { + u'cn': u'test_rule', + u'description': u'Certificate mapping and matching rule for test ' + u'purposes', + u'ipacertmapissuer': DN('CN=CA,O=EXAMPLE.ORG'), + u'ipacertmapmaprule': u'arbitrary free-form mapping rule defined and ' + u'consumed by SSSD', + u'ipacertmapmatchrule': u'arbitrary free-form matching rule defined ' + u'and consumed by SSSD', + u'associateddomain': u'example.org', + u'ipacertmappriority': u'1', +} + +certmaprule_update_params = { + u'description': u'Changed description', + u'ipacertmapissuer': DN('CN=Changed CA,O=OTHER.ORG'), + u'ipacertmapmaprule': u'changed arbitrary mapping rule', + u'ipacertmapmatchrule': u'changed arbitrary maching rule', + u'associateddomain': u'changed.example.org', + u'ipacertmappriority': u'5', +} + +certmaprule_optional_params = ( + 'description', + 'ipacertmapissuer', + 'ipacertmapmaprule', + 'ipacertmapmatchrule', + 'ipaassociateddomain', + 'ipacertmappriority', +) + +def dontfill_idfn(dont_fill): + return u"dont_fill=({})".format(', '.join([ + u"{}".format(d) for d in dont_fill + ])) + + +def update_idfn(update): + return ', '.join(["{}: {}".format(k, v) for k, v in update.items()]) + + +@pytest.fixture(scope='class') +def certmap_rule(request): + tracker = CertmapruleTracker(**certmaprule_create_params) + return tracker.make_fixture(request) + + +class TestCRUD(XMLRPC_test): + @pytest.mark.parametrize( + 'dont_fill', + itertools.chain(*[ + itertools.combinations(certmaprule_optional_params, l) + for l in range(len(certmaprule_optional_params)+1) + ]), + ids=dontfill_idfn, + ) + def test_create(self, dont_fill, certmap_rule): + certmap_rule.ensure_missing() + try: + certmap_rule.create(dont_fill) + finally: + certmap_rule.ensure_missing() + + def test_retrieve(self, certmap_rule): + certmap_rule.ensure_exists() + certmap_rule.retrieve() + + def test_find(self, certmap_rule): + certmap_rule.ensure_exists() + certmap_rule.find() + + @pytest.mark.parametrize('update', [ + dict(u) for l in range(1, len(certmaprule_update_params)+1) + for u in itertools.combinations( + certmaprule_update_params.items(), l) + ], + ids=update_idfn, + ) + def test_update(self, update, certmap_rule): + certmap_rule.ensure_missing() + certmap_rule.ensure_exists() + certmap_rule.update(update, {o: [v] for o, v in update.items()}) + + def test_delete(self, certmap_rule): + certmap_rule.ensure_exists() + certmap_rule.delete() + + +class TestEnableDisable(XMLRPC_test): + def test_disable(self, certmap_rule): + certmap_rule.ensure_exists() + certmap_rule.disable() + + def test_enable(self, certmap_rule): + certmap_rule.ensure_exists() + certmap_rule.enable() diff --git a/ipatests/test_xmlrpc/tracker/certmap_plugin.py b/ipatests/test_xmlrpc/tracker/certmap_plugin.py new file mode 100644 index 0000000..76022bf --- /dev/null +++ b/ipatests/test_xmlrpc/tracker/certmap_plugin.py @@ -0,0 +1,167 @@ +# +# Copyright (C) 2017 FreeIPA Contributors see COPYING for license +# + +from ipapython.dn import DN +from ipatests.test_xmlrpc.tracker.base import Tracker +from ipatests.test_xmlrpc import objectclasses +from ipatests.util import assert_deepequal + + +class CertmapruleTracker(Tracker): + """ Tracker for testin certmaprule plugin """ + retrieve_keys = { + u'dn', + u'cn', + u'description', + u'ipacertmapissuer', + u'ipacertmapmaprule', + u'ipacertmapmatchrule', + u'associateddomain', + u'ipacertmappriority', + u'ipaenabledflag' + } + retrieve_all_keys = retrieve_keys | {u'objectclass'} + create_keys = retrieve_keys | {u'objectclass'} + update_keys = retrieve_keys - {u'dn'} + + def __init__(self, cn, description, ipacertmapissuer, ipacertmapmaprule, + ipacertmapmatchrule, associateddomain, ipacertmappriority, + default_version=None): + super(CertmapruleTracker, self).__init__( + default_version=default_version) + + self.dn = DN((u'cn', cn,), + self.api.env.container_certmaprules, + self.api.env.basedn) + self.options = { + u'description': description, + u'ipacertmapissuer': ipacertmapissuer, + u'ipacertmapmaprule': ipacertmapmaprule, + u'ipacertmapmatchrule': ipacertmapmatchrule, + u'associateddomain': associateddomain, + u'ipacertmappriority': ipacertmappriority, + } + + def make_create_command(self, dont_fill=()): + kwargs = {k: v for k, v in self.options.items() if k not in dont_fill} + + return self.make_command('certmaprule_add', self.name, **kwargs) + + def track_create(self, dont_fill=()): + self.attrs = { + 'dn': self.dn, + 'cn': [self.name], + 'ipaenabledflag': [u'TRUE'], + 'objectclass': objectclasses.certmaprule, + } + self.attrs.update({ + k: [v] for k, v in self.options.items() if k not in dont_fill + }) + self.exists = True + + def check_create(self, result): + assert_deepequal(dict( + value=self.name, + summary=u'Added Certificate Identity Mapping Rule "{}"' + u''.format(self.name), + result=self.filter_attrs(self.create_keys), + ), result) + + def create(self, dont_fill=()): + self.track_create(dont_fill) + command = self.make_create_command(dont_fill) + result = command() + self.check_create(result) + + def make_delete_command(self): + return self.make_command('certmaprule_del', self.name) + + def check_delete(self, result): + assert_deepequal( + dict( + value=[self.name], + summary=u'Deleted Certificate Identity Mapping Rule "{}"' + ''.format(self.name), + result=dict(failed=[]), + ), + result + ) + + def make_retrieve_command(self, all=False, raw=False): + return self.make_command('certmaprule_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('certmaprule_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 Certificate Identity Mapping Rule matched', + result=[expected], + ), + result + ) + + def make_update_command(self, updates): + return self.make_command('certmaprule_mod', self.name, **updates) + + def check_update(self, result, extra_keys=()): + assert_deepequal( + dict( + value=self.name, + summary=u'Modified Certificate Identity Mapping Rule "{}"' + u''.format(self.name), + result=self.filter_attrs(self.update_keys | set(extra_keys)), + ), + result + ) + + def make_enable_command(self): + return self.make_command('certmaprule_enable', self.name) + + def check_enable(self, result): + assert_deepequal( + dict( + value=self.name, + summary=u'Enabled Certificate Identity Mapping Rule "{}"' + u''.format(self.name), + result=True, + ), + result + ) + + def make_disable_command(self): + return self.make_command('certmaprule_disable', self.name) + + def check_disable(self, result): + assert_deepequal( + dict( + value=self.name, + summary=u'Disabled Certificate Identity Mapping Rule "{}"' + u''.format(self.name), + result=True, + ), + result + ) From a4bbe4441609058fa4a46c39275fbe3a633a9f17 Mon Sep 17 00:00:00 2001 From: David Kupka <dku...@redhat.com> Date: Tue, 24 Jan 2017 16:21:54 +0100 Subject: [PATCH 3/3] tests: certmap: Test ACI works as expected https://fedorahosted.org/freeipa/ticket/6542 --- ipatests/test_xmlrpc/test_certmap_plugin.py | 260 ++++++++++++++++++++++++++++ 1 file changed, 260 insertions(+) diff --git a/ipatests/test_xmlrpc/test_certmap_plugin.py b/ipatests/test_xmlrpc/test_certmap_plugin.py index 9343f9a..00f5b69 100644 --- a/ipatests/test_xmlrpc/test_certmap_plugin.py +++ b/ipatests/test_xmlrpc/test_certmap_plugin.py @@ -2,12 +2,18 @@ # Copyright (C) 2017 FreeIPA Contributors see COPYING for license # +from contextlib import contextmanager import itertools +from nose.tools import assert_raises import pytest +from ipalib import api, errors from ipapython.dn import DN from ipatests.test_xmlrpc.xmlrpc_test import XMLRPC_test from ipatests.test_xmlrpc.tracker.certmap_plugin import CertmapruleTracker +from ipatests.util import assert_deepequal +from ipatests.util import change_principal, unlock_principal_password + certmaprule_create_params = { u'cn': u'test_rule', @@ -40,6 +46,17 @@ 'ipacertmappriority', ) +certmaprule_permissions = { + u'C': u'System: Add Certmap Rules', + u'R': u'System: Read Certmap Rules', + u'U': u'System: Modify Certmap Rules', + u'D': u'System: Delete Certmap Rules', +} + +CERTMAP_USER = u'cuser' +CERTMAP_PASSWD = 'Secret123' + + def dontfill_idfn(dont_fill): return u"dont_fill=({})".format(', '.join([ u"{}".format(d) for d in dont_fill @@ -105,3 +122,246 @@ def test_disable(self, certmap_rule): def test_enable(self, certmap_rule): certmap_rule.ensure_exists() certmap_rule.enable() + + +class Result(Exception): + def __init__(self, value): + self.value = value + + +@contextmanager +def execute_with_expected(user, password, perms, exps, ok_expected=None): + """ + Run command as specified user. Check exception or return value + according provided rules. + + @param user Change to this user before calling the command + @param password User to change user + @param perms User has those permissions + @param exps Iterable containing tuple + (permission, exception_class, expected_result,) + If permission is missing command must raise exception of + exception_class. If exception class is None command must + raise Result(expected_result) + @param ok_expected When no permission is missing command must raise + Result(ok_expected) + """ + with change_principal(user, password): + for perm, exception, expected in exps: + if perm not in perms: + if exception: + with assert_raises(exception): + yield + else: + try: + yield + except Result as got: + assert_deepequal(expected, got.value) + else: + if ok_expected: + assert("Command didn't raise Result") + break + else: + try: + yield + except Result as got: + if ok_expected: + assert_deepequal(ok_expected, got.value) + else: + if ok_expected: + assert("Command didn't raise Result") + + +def permissions_idfn(perms): + i = [] + for short_name, long_name in certmaprule_permissions.items(): + if long_name in perms: + i.append(short_name) + else: + i.append('-') + return ''.join(i) + + +@pytest.fixture( + scope='class', + params=itertools.chain(*[ + itertools.combinations(certmaprule_permissions.values(), l) + for l in range(len(certmaprule_permissions.values())+1) + ]), + ids=permissions_idfn, +) +def certmap_user_permissions(request): + tmp_password = u'Initial123' + + priv_name = u'test_certmap_privilege' + role_name = u'test_certmap_role' + + api.Command.user_add(CERTMAP_USER, givenname=u'Certmap', sn=u'User', + userpassword=tmp_password) + unlock_principal_password(CERTMAP_USER, tmp_password, + CERTMAP_PASSWD) + + api.Command.privilege_add(priv_name) + for perm_name in request.param: + api.Command.privilege_add_permission(priv_name, permission=perm_name) + api.Command.role_add(role_name) + api.Command.role_add_privilege(role_name, privilege=priv_name) + api.Command.role_add_member(role_name, user=CERTMAP_USER) + + def finalize(): + try: + api.Command.user_del(CERTMAP_USER) + except Exception: + pass + try: + api.Command.role_del(role_name) + except Exception: + pass + try: + api.Command.privilege_del(priv_name) + except Exception: + pass + request.addfinalizer(finalize) + + return request.param + + +class TestPermission(XMLRPC_test): + def test_create(self, certmap_rule, certmap_user_permissions): + certmap_rule.ensure_missing() + + with execute_with_expected( + CERTMAP_USER, + CERTMAP_PASSWD, + certmap_user_permissions, + [ + (u'System: Add Certmap Rules', errors.ACIError, None,), + (u'System: Read Certmap Rules', errors.NotFound, None,), + ], + ): + certmap_rule.create(), + + # Tracker sets 'exists' to True even when the create does not + # succeed so ensure_missing wouldn't be reliable here + try: + certmap_rule.delete() + except Exception: + pass + + def test_retrieve(self, certmap_rule, certmap_user_permissions): + certmap_rule.ensure_exists() + + with execute_with_expected( + CERTMAP_USER, + CERTMAP_PASSWD, + certmap_user_permissions, + [ + (u'System: Read Certmap Rules', errors.NotFound, None,), + ], + ): + certmap_rule.retrieve() + + def test_find(self, certmap_rule, certmap_user_permissions): + certmap_rule.ensure_exists() + + expected_without_read = { + u'count': 0, + u'result': (), + u'summary': u'0 Certificate Identity Mapping Rules matched', + u'truncated': False, + } + expected_ok = { + u'count': 1, + u'result': [{ + k: (v,) for k, v in certmaprule_create_params.items() + }], + u'summary': u'1 Certificate Identity Mapping Rule matched', + u'truncated': False, + } + expected_ok[u'result'][0][u'dn'] = DN( + (u'cn', expected_ok[u'result'][0][u'cn'][0]), + api.env.container_certmaprules, + api.env.basedn, + ) + expected_ok[u'result'][0][u'ipaenabledflag'] = (u'TRUE',) + with execute_with_expected( + CERTMAP_USER, + CERTMAP_PASSWD, + certmap_user_permissions, + [ + (u'System: Read Certmap Rules', None, expected_without_read,), + ], + expected_ok, + ): + find = certmap_rule.make_find_command() + got = find(**{k: v for k, v in certmaprule_create_params.items() + if k is not u'dn'}) + raise Result(got) + + def test_update(self, certmap_rule, certmap_user_permissions): + certmap_rule.ensure_missing() + certmap_rule.ensure_exists() + + with execute_with_expected( + CERTMAP_USER, + CERTMAP_PASSWD, + certmap_user_permissions, + [ + (u'System: Read Certmap Rules', errors.NotFound, None,), + (u'System: Modify Certmap Rules', errors.ACIError, None,), + ], + ): + certmap_rule.update( + certmaprule_update_params, + {o: [v] for o, v in certmaprule_update_params.items()}, + ) + + def test_delete(self, certmap_rule, certmap_user_permissions): + certmap_rule.ensure_exists() + + with execute_with_expected( + CERTMAP_USER, + CERTMAP_PASSWD, + certmap_user_permissions, + [ + (u'System: Delete Certmap Rules', errors.ACIError, None,), + ], + ): + certmap_rule.delete() + + # Tracker sets 'exists' to False even when the delete does not + # succeed so ensure_missing wouldn't be reliable here + try: + certmap_rule.delete() + except Exception: + pass + + def test_enable(self, certmap_rule, certmap_user_permissions): + certmap_rule.ensure_exists() + certmap_rule.disable() + + with execute_with_expected( + CERTMAP_USER, + CERTMAP_PASSWD, + certmap_user_permissions, + [ + (u'System: Read Certmap Rules', errors.NotFound, None,), + (u'System: Modify Certmap Rules', errors.ACIError, None,), + ], + ): + certmap_rule.enable() + + def test_disable(self, certmap_rule, certmap_user_permissions): + certmap_rule.ensure_exists() + certmap_rule.enable() + + with execute_with_expected( + CERTMAP_USER, + CERTMAP_PASSWD, + certmap_user_permissions, + [ + (u'System: Read Certmap Rules', errors.NotFound, None,), + (u'System: Modify Certmap Rules', errors.ACIError, None,), + ], + ): + certmap_rule.disable()
-- 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