This patch makes all categories and their equivalent members mutually
exclusive like in the HBAC plugin. So if you have usercat='all' you
can't add users.
Added test cases for these as well.
I also modified the default list of attributes to include the RunAs
attributes.
rob
>From cee85b3cc82153ab3f96050a5ea8033b8c55ea18 Mon Sep 17 00:00:00 2001
From: Rob Crittenden <rcrit...@redhat.com>
Date: Mon, 12 Dec 2011 17:11:32 -0500
Subject: [PATCH] When the category is all do not allow members, and vice
versa.
This is what we already do in the HBAC plugin, this ports it to Sudo.
If a category (user, host, etc) is u'all' then we don't allow individual
members be added. Conversely if there are members we don't allow the
category be set to u'all'.
https://fedorahosted.org/freeipa/ticket/1440
---
ipalib/plugins/sudorule.py | 87 +++++++++++++++++++++++++
tests/test_xmlrpc/test_sudorule_plugin.py | 99 +++++++++++++++++++++++++++-
2 files changed, 182 insertions(+), 4 deletions(-)
diff --git a/ipalib/plugins/sudorule.py b/ipalib/plugins/sudorule.py
index 93ca03f0170d922b91eff45ec2f42871336973f1..3c998d98e0bcec979b161c0b0cd4ef3fc6386cc8 100644
--- a/ipalib/plugins/sudorule.py
+++ b/ipalib/plugins/sudorule.py
@@ -20,6 +20,7 @@
from ipalib import api, errors
from ipalib import Str, StrEnum
from ipalib.plugins.baseldap import *
+from ipalib.plugins.hbacrule import is_all
from ipalib import _, ngettext
__doc__ = _("""
@@ -77,6 +78,8 @@ class sudorule(LDAPObject):
'description', 'usercategory', 'hostcategory',
'cmdcategory', 'memberuser', 'memberhost',
'memberallowcmd', 'memberdenycmd', 'ipasudoopt',
+ 'ipasudorunas', 'ipasudorunasgroup',
+ 'ipasudorunasusercategory', 'ipasudorunasgroupcategory',
]
uuid_attribute = 'ipauniqueid'
rdn_attribute = 'ipauniqueid'
@@ -233,6 +236,26 @@ class sudorule_mod(LDAPUpdate):
msg_summary = _('Modified Sudo Rule "%(value)s"')
+ def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ try:
+ (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+ except errors.NotFound:
+ self.obj.handle_not_found(*keys)
+
+ if is_all(options, 'usercategory') and 'memberuser' in _entry_attrs:
+ raise errors.MutuallyExclusiveError(reason="user category cannot be set to 'all' while there are users")
+ if is_all(options, 'hostcategory') and 'memberhost' in _entry_attrs:
+ raise errors.MutuallyExclusiveError(reason="host category cannot be set to 'all' while there are hosts")
+ if is_all(options, 'cmdcategory') and ('memberallowcmd' or
+ 'memberdenywcmd') in _entry_attrs:
+ raise errors.MutuallyExclusiveError(reason="command category cannot be set to 'all' while there are allow or deny commands")
+ if is_all(options, 'ipasudorunasusercategory') and 'ipasudorunas' in _entry_attrs:
+ raise errors.MutuallyExclusiveError(reason="user runAs category cannot be set to 'all' while there are users")
+ if is_all(options, 'ipasudorunasgroupcategory') and 'ipasudorunasgroup' in _entry_attrs:
+ raise errors.MutuallyExclusiveError(reason="group runAs category cannot be set to 'all' while there are groups")
+
+ return dn
+
api.register(sudorule_mod)
@@ -306,6 +329,16 @@ class sudorule_add_allow_command(LDAPAddMember):
member_attributes = ['memberallowcmd']
member_count_out = ('%i object added.', '%i objects added.')
+ def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ try:
+ (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+ except errors.NotFound:
+ self.obj.handle_not_found(*keys)
+ if 'cmdcategory' in _entry_attrs and \
+ _entry_attrs['cmdcategory'][0].lower() == 'all':
+ raise errors.MutuallyExclusiveError(reason="commands cannot be added when command category='all'")
+ return dn
+
api.register(sudorule_add_allow_command)
@@ -324,6 +357,16 @@ class sudorule_add_deny_command(LDAPAddMember):
member_attributes = ['memberdenycmd']
member_count_out = ('%i object added.', '%i objects added.')
+ def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ try:
+ (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+ except errors.NotFound:
+ self.obj.handle_not_found(*keys)
+ if 'cmdcategory' in _entry_attrs and \
+ _entry_attrs['cmdcategory'][0].lower() == 'all':
+ raise errors.MutuallyExclusiveError(reason="commands cannot be added when command category='all'")
+ return dn
+
api.register(sudorule_add_deny_command)
@@ -342,6 +385,16 @@ class sudorule_add_user(LDAPAddMember):
member_attributes = ['memberuser']
member_count_out = ('%i object added.', '%i objects added.')
+ def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ try:
+ (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+ except errors.NotFound:
+ self.obj.handle_not_found(*keys)
+ if 'usercategory' in _entry_attrs and \
+ _entry_attrs['usercategory'][0].lower() == 'all':
+ raise errors.MutuallyExclusiveError(reason="users cannot be added when user category='all'")
+ return dn
+
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
completed_external = 0
# Sift through the user failures. We assume that these are all
@@ -410,6 +463,16 @@ class sudorule_add_host(LDAPAddMember):
member_attributes = ['memberhost']
member_count_out = ('%i object added.', '%i objects added.')
+ def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ try:
+ (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+ except errors.NotFound:
+ self.obj.handle_not_found(*keys)
+ if 'hostcategory' in _entry_attrs and \
+ _entry_attrs['hostcategory'][0].lower() == 'all':
+ raise errors.MutuallyExclusiveError(reason="hosts cannot be added when host category='all'")
+ return dn
+
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
completed_external = 0
# Sift through the host failures. We assume that these are all
@@ -479,6 +542,18 @@ class sudorule_add_runasuser(LDAPAddMember):
member_attributes = ['ipasudorunas']
member_count_out = ('%i object added.', '%i objects added.')
+ def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ try:
+ (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+ except errors.NotFound:
+ self.obj.handle_not_found(*keys)
+ if ('ipasudorunasusercategory' or 'ipasudorunasgroupcategory') \
+ in _entry_attrs and \
+ (_entry_attrs['ipasudorunasusercategory'][0].lower() == 'all' or \
+ _entry_attrs['ipasudorunasgroupcategory'][0].lower() == 'all'):
+ raise errors.MutuallyExclusiveError(reason="users cannot be added when runAs user or runAs group category='all'")
+ return dn
+
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
completed_external = 0
# Sift through the user failures. We assume that these are all
@@ -547,6 +622,18 @@ class sudorule_add_runasgroup(LDAPAddMember):
member_attributes = ['ipasudorunasgroup']
member_count_out = ('%i object added.', '%i objects added.')
+ def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ try:
+ (_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+ except errors.NotFound:
+ self.obj.handle_not_found(*keys)
+ if ('ipasudorunasusercategory' or 'ipasudorunasgroupcategory') \
+ in _entry_attrs and \
+ (_entry_attrs['ipasudorunasusercategory'][0].lower() == 'all' or \
+ _entry_attrs['ipasudorunasgroupcategory'][0].lower() == 'all'):
+ raise errors.MutuallyExclusiveError(reason="users cannot be added when runAs user or runAs group category='all'")
+ return dn
+
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
completed_external = 0
# Sift through the group failures. We assume that these are all
diff --git a/tests/test_xmlrpc/test_sudorule_plugin.py b/tests/test_xmlrpc/test_sudorule_plugin.py
index 88e31c72c5b4c823c11649c18417e51d67d77f9b..de1bba5fbf7fd877a4840eb3f454a757e5dc7b38 100644
--- a/tests/test_xmlrpc/test_sudorule_plugin.py
+++ b/tests/test_xmlrpc/test_sudorule_plugin.py
@@ -47,7 +47,7 @@ class test_sudorule(XMLRPC_test):
test_denycommand = u'/usr/bin/testdenysudocmd1'
test_runasuser = u'manager'
test_runasgroup = u'manager'
- test_catagory = u'all'
+ test_category = u'all'
test_option = u'authenticate'
def test_0_sudorule_add(self):
@@ -520,7 +520,99 @@ class test_sudorule(XMLRPC_test):
assert 'memberdenycmd_sudocmd' not in entry
assert 'memberdenycmd_sudocmdgroup' not in entry
- def test_c_sudorule_clear_testing_data(self):
+ def test_c_sudorule_exclusiveuser(self):
+ """
+ Test adding a user to an Sudo rule when usercat='all'
+ """
+ api.Command['sudorule_mod'](self.rule_name, usercategory=u'all')
+ try:
+ api.Command['sudorule_add_user'](self.rule_name, users='admin')
+ except errors.MutuallyExclusiveError:
+ pass
+ api.Command['sudorule_mod'](self.rule_name, usercategory=u'')
+
+ def test_d_sudorule_exclusiveuser(self):
+ """
+ Test setting usercat='all' in an Sudo rule when there are users
+ """
+ api.Command['sudorule_add_user'](self.rule_name, users='admin')
+ try:
+ api.Command['sudorule_mod'](self.rule_name, usercategory=u'all')
+ except errors.MutuallyExclusiveError:
+ pass
+ finally:
+ api.Command['sudorule_remove_user'](self.rule_name, users='admin')
+
+ def test_e_sudorule_exclusivehost(self):
+ """
+ Test adding a host to an Sudo rule when hostcat='all'
+ """
+ api.Command['sudorule_mod'](self.rule_name, hostcategory=u'all')
+ try:
+ api.Command['sudorule_add_host'](self.rule_name, host=self.test_host)
+ except errors.MutuallyExclusiveError:
+ pass
+ api.Command['sudorule_mod'](self.rule_name, hostcategory=u'')
+
+ def test_f_sudorule_exclusivehost(self):
+ """
+ Test setting hostcat='all' in an Sudo rule when there are hosts
+ """
+ api.Command['sudorule_add_host'](self.rule_name, host=self.test_host)
+ try:
+ api.Command['sudorule_mod'](self.rule_name, hostcategory=u'all')
+ except errors.MutuallyExclusiveError:
+ pass
+ finally:
+ api.Command['sudorule_remove_host'](self.rule_name, host=self.test_host)
+
+ def test_g_sudorule_exclusivecommand(self):
+ """
+ Test adding a command to an Sudo rule when cmdcategory='all'
+ """
+ api.Command['sudorule_mod'](self.rule_name, cmdcategory=u'all')
+ try:
+ api.Command['sudorule_add_allow_command'](self.rule_name, sudocmd=self.test_command)
+ except errors.MutuallyExclusiveError:
+ pass
+ api.Command['sudorule_mod'](self.rule_name, cmdcategory=u'')
+
+ def test_h_sudorule_exclusivecommand(self):
+ """
+ Test setting cmdcategory='all' in an Sudo rule when there are commands
+ """
+ api.Command['sudorule_add_allow_command'](self.rule_name, sudocmd=self.test_command)
+ try:
+ api.Command['sudorule_mod'](self.rule_name, cmdcategory=u'all')
+ except errors.MutuallyExclusiveError:
+ pass
+ finally:
+ api.Command['sudorule_remove_allow_command'](self.rule_name, sudocmd=self.test_command)
+
+ def test_i_sudorule_exclusiverunas(self):
+ """
+ Test adding a runasuser to an Sudo rule when ipasudorunasusercategory='all'
+ """
+ api.Command['sudorule_mod'](self.rule_name, ipasudorunasusercategory=u'all')
+ try:
+ api.Command['sudorule_add_runasuser'](self.rule_name, sudocmd=self.test_user)
+ except errors.MutuallyExclusiveError:
+ pass
+ api.Command['sudorule_mod'](self.rule_name, ipasudorunasusercategory=u'')
+
+ def test_j_sudorule_exclusiverunas(self):
+ """
+ Test setting ipasudorunasusercategory='all' in an Sudo rule when there are runas users
+ """
+ api.Command['sudorule_add_runasuser'](self.rule_name, user=self.test_user)
+ try:
+ api.Command['sudorule_mod'](self.rule_name, ipasudorunasusercategory=u'all')
+ except errors.MutuallyExclusiveError:
+ pass
+ finally:
+ api.Command['sudorule_remove_runasuser'](self.rule_name, user=self.test_command)
+
+ def test_k_sudorule_clear_testing_data(self):
"""
Clear data for Sudo rule plugin testing.
"""
@@ -533,8 +625,7 @@ class test_sudorule(XMLRPC_test):
api.Command['sudocmdgroup_del'](self.test_sudoallowcmdgroup)
api.Command['sudocmdgroup_del'](self.test_sudodenycmdgroup)
-
- def test_f_sudorule_del(self):
+ def test_l_sudorule_del(self):
"""
Test deleting a Sudo rule using `xmlrpc.sudorule_del`.
"""
--
1.7.6
_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel