summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Crittenden <rcritten@redhat.com>2012-03-01 14:02:28 -0500
committerRob Crittenden <rcritten@redhat.com>2012-03-01 21:02:33 -0500
commitd55d8bfa7ed1d3617274c9f53974e7bf5209cc4e (patch)
treec5b69a401c0c8ae3dba503bf0bb7137cd641e382
parent31eebda584d556454104a8fbf26974b6b49d9589 (diff)
downloadfreeipa.git-d55d8bfa7ed1d3617274c9f53974e7bf5209cc4e.tar.gz
freeipa.git-d55d8bfa7ed1d3617274c9f53974e7bf5209cc4e.tar.xz
freeipa.git-d55d8bfa7ed1d3617274c9f53974e7bf5209cc4e.zip
Add support for sudoOrder
Update ipaSudoRule objectClass on upgrades to add new attributes. Ensure uniqueness of sudoOrder in rules. The attributes sudoNotBefore and sudoNotAfter are being added to schema but not as Params. https://fedorahosted.org/freeipa/ticket/1314
-rw-r--r--API.txt9
-rw-r--r--install/share/65ipasudo.ldif (renamed from install/share/60ipasudo.ldif)2
-rw-r--r--install/share/Makefile.am2
-rw-r--r--install/updates/10-sudo.update2
-rw-r--r--ipalib/plugins/sudorule.py41
-rw-r--r--ipaserver/install/dsinstance.py2
-rw-r--r--tests/test_xmlrpc/test_sudorule_plugin.py45
7 files changed, 94 insertions, 9 deletions
diff --git a/API.txt b/API.txt
index 88684dfa..9ba3ce4a 100644
--- a/API.txt
+++ b/API.txt
@@ -2831,7 +2831,7 @@ output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), None)
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
output: Output('value', <type 'unicode'>, None)
command: sudorule_add
-args: 1,14,3
+args: 1,15,3
arg: Str('cn', attribute=True, cli_name='sudorule_name', multivalue=False, primary_key=True, required=True)
option: Str('description', attribute=True, cli_name='desc', multivalue=False, required=False)
option: StrEnum('usercategory', attribute=True, cli_name='usercat', multivalue=False, required=False, values=(u'all',))
@@ -2839,6 +2839,7 @@ option: StrEnum('hostcategory', attribute=True, cli_name='hostcat', multivalue=F
option: StrEnum('cmdcategory', attribute=True, cli_name='cmdcat', multivalue=False, required=False, values=(u'all',))
option: StrEnum('ipasudorunasusercategory', attribute=True, cli_name='runasusercat', multivalue=False, required=False, values=(u'all',))
option: StrEnum('ipasudorunasgroupcategory', attribute=True, cli_name='runasgroupcat', multivalue=False, required=False, values=(u'all',))
+option: Int('sudoorder', attribute=True, cli_name='order', default=0, multivalue=False, required=False)
option: Str('externaluser', attribute=True, cli_name='externaluser', multivalue=False, required=False)
option: Str('ipasudorunasextuser', attribute=True, cli_name='runasexternaluser', multivalue=False, required=False)
option: Str('ipasudorunasextgroup', attribute=True, cli_name='runasexternalgroup', multivalue=False, required=False)
@@ -2936,7 +2937,7 @@ args: 1,0,1
arg: Str('cn', attribute=True, cli_name='sudorule_name', multivalue=False, primary_key=True, query=True, required=True)
output: Output('result', None, None)
command: sudorule_find
-args: 1,16,4
+args: 1,17,4
arg: Str('criteria?', noextrawhitespace=False)
option: Str('cn', attribute=True, autofill=False, cli_name='sudorule_name', multivalue=False, primary_key=True, query=True, required=False)
option: Str('description', attribute=True, autofill=False, cli_name='desc', multivalue=False, query=True, required=False)
@@ -2945,6 +2946,7 @@ option: StrEnum('hostcategory', attribute=True, autofill=False, cli_name='hostca
option: StrEnum('cmdcategory', attribute=True, autofill=False, cli_name='cmdcat', multivalue=False, query=True, required=False, values=(u'all',))
option: StrEnum('ipasudorunasusercategory', attribute=True, autofill=False, cli_name='runasusercat', multivalue=False, query=True, required=False, values=(u'all',))
option: StrEnum('ipasudorunasgroupcategory', attribute=True, autofill=False, cli_name='runasgroupcat', multivalue=False, query=True, required=False, values=(u'all',))
+option: Int('sudoorder', attribute=True, autofill=False, cli_name='order', default=0, multivalue=False, query=True, required=False)
option: Str('externaluser', attribute=True, autofill=False, cli_name='externaluser', multivalue=False, query=True, required=False)
option: Str('ipasudorunasextuser', attribute=True, autofill=False, cli_name='runasexternaluser', multivalue=False, query=True, required=False)
option: Str('ipasudorunasextgroup', attribute=True, autofill=False, cli_name='runasexternalgroup', multivalue=False, query=True, required=False)
@@ -2959,7 +2961,7 @@ output: ListOfEntries('result', (<type 'list'>, <type 'tuple'>), Gettext('A list
output: Output('count', <type 'int'>, None)
output: Output('truncated', <type 'bool'>, None)
command: sudorule_mod
-args: 1,16,3
+args: 1,17,3
arg: Str('cn', attribute=True, cli_name='sudorule_name', multivalue=False, primary_key=True, query=True, required=True)
option: Str('description', attribute=True, autofill=False, cli_name='desc', multivalue=False, required=False)
option: StrEnum('usercategory', attribute=True, autofill=False, cli_name='usercat', multivalue=False, required=False, values=(u'all',))
@@ -2967,6 +2969,7 @@ option: StrEnum('hostcategory', attribute=True, autofill=False, cli_name='hostca
option: StrEnum('cmdcategory', attribute=True, autofill=False, cli_name='cmdcat', multivalue=False, required=False, values=(u'all',))
option: StrEnum('ipasudorunasusercategory', attribute=True, autofill=False, cli_name='runasusercat', multivalue=False, required=False, values=(u'all',))
option: StrEnum('ipasudorunasgroupcategory', attribute=True, autofill=False, cli_name='runasgroupcat', multivalue=False, required=False, values=(u'all',))
+option: Int('sudoorder', attribute=True, autofill=False, cli_name='order', default=0, multivalue=False, required=False)
option: Str('externaluser', attribute=True, autofill=False, cli_name='externaluser', multivalue=False, required=False)
option: Str('ipasudorunasextuser', attribute=True, autofill=False, cli_name='runasexternaluser', multivalue=False, required=False)
option: Str('ipasudorunasextgroup', attribute=True, autofill=False, cli_name='runasexternalgroup', multivalue=False, required=False)
diff --git a/install/share/60ipasudo.ldif b/install/share/65ipasudo.ldif
index 61c73c08..7a85c865 100644
--- a/install/share/60ipasudo.ldif
+++ b/install/share/65ipasudo.ldif
@@ -32,7 +32,7 @@ attributeTypes: (2.16.840.1.113730.3.8.7.12 NAME 'hostMask' DESC 'IP mask to ide
## Attribute to store sudo command
attributeTypes: (2.16.840.1.113730.3.8.7.13 NAME 'sudoCmd' DESC 'Command(s) to be executed by sudo' EQUALITY caseExactMatch ORDERING caseExactMatch SUBSTR caseExactSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' )
## Object class for SUDO rules
-objectClasses: (2.16.840.1.113730.3.8.8.1 NAME 'ipaSudoRule' SUP ipaAssociation STRUCTURAL MAY ( externalUser $ externalHost $ hostMask $ memberAllowCmd $ memberDenyCmd $ cmdCategory $ ipaSudoOpt $ ipaSudoRunAs $ ipaSudoRunAsExtUser $ ipaSudoRunAsUserCategory $ ipaSudoRunAsGroup $ ipaSudoRunAsExtGroup $ ipaSudoRunAsGroupCategory ) X-ORIGIN 'IPA v2' )
+objectClasses: (2.16.840.1.113730.3.8.8.1 NAME 'ipaSudoRule' SUP ipaAssociation STRUCTURAL MAY ( externalUser $ externalHost $ hostMask $ memberAllowCmd $ memberDenyCmd $ cmdCategory $ ipaSudoOpt $ ipaSudoRunAs $ ipaSudoRunAsExtUser $ ipaSudoRunAsUserCategory $ ipaSudoRunAsGroup $ ipaSudoRunAsExtGroup $ ipaSudoRunAsGroupCategory $ sudoNotBefore $ sudoNotAfter $$ sudoOrder ) X-ORIGIN 'IPA v2' )
## Object class for SUDO commands
objectClasses: (2.16.840.1.113730.3.8.8.2 NAME 'ipaSudoCmd' DESC 'IPA object class for SUDO command' STRUCTURAL MUST ( ipaUniqueID $ sudoCmd ) MAY ( memberOf $ description ) X-ORIGIN 'IPA v2' )
## Object class for groups of the SUDO commands
diff --git a/install/share/Makefile.am b/install/share/Makefile.am
index eefa3534..243fc2a1 100644
--- a/install/share/Makefile.am
+++ b/install/share/Makefile.am
@@ -9,7 +9,7 @@ app_DATA = \
60basev2.ldif \
60basev3.ldif \
60ipadns.ldif \
- 60ipasudo.ldif \
+ 65ipasudo.ldif \
anonymous-vlv.ldif \
bootstrap-template.ldif \
caJarSigningCert.cfg.template \
diff --git a/install/updates/10-sudo.update b/install/updates/10-sudo.update
index 88bdc3ce..a12da004 100644
--- a/install/updates/10-sudo.update
+++ b/install/updates/10-sudo.update
@@ -38,3 +38,5 @@ add:attributeTypes: ( 1.3.6.1.4.1.15953.9.1.10
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
X-ORIGIN 'SUDO' )
replace:objectClasses:( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' DESC 'Sudoer Entries' STRUCTURAL MUST cn MAY ( sudoUser $$ sudoHost $$ sudoCommand $$ sudoRunAs $$ sudoOption $$ description ) X-ORIGIN 'SUDO' )::( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL DESC 'Sudoer Entries' MUST ( cn ) MAY ( sudoUser $$ sudoHost $$ sudoCommand $$ sudoRunAs $$ sudoRunAsUser $$ sudoRunAsGroup $$ sudoOption $$ sudoNotBefore $$ sudoNotAfter $$ sudoOrder $$ description ) X-ORIGIN 'SUDO')
+
+replace:objectClasses: ( 2.16.840.1.113730.3.8.8.1 NAME 'ipaSudoRule' SUP ipaAssociation STRUCTURAL MAY ( externalUser $$ externalHost $$ hostMask $$ memberAllowCmd $$ memberDenyCmd $$ cmdCategory $$ ipaSudoOpt $$ ipaSudoRunAs $$ ipaSudoRunAsExtUser $$ ipaSudoRunAsUserCategory $$ ipaSudoRunAsGroup $$ ipaSudoRunAsExtGroup $$ ipaSudoRunAsGroupCategory ) X-ORIGIN 'IPA v2' )::(2.16.840.1.113730.3.8.8.1 NAME 'ipaSudoRule' SUP ipaAssociation STRUCTURAL MAY ( externalUser $$ externalHost $$ hostMask $$ memberAllowCmd $$ memberDenyCmd $$ cmdCategory $$ ipaSudoOpt $$ ipaSudoRunAs $$ ipaSudoRunAsExtUser $$ ipaSudoRunAsUserCategory $$ ipaSudoRunAsGroup $$ ipaSudoRunAsExtGroup $$ ipaSudoRunAsGroupCategory $$ sudoNotBefore $$ sudoNotAfter $$ sudoOrder) X-ORIGIN 'IPA v2' )
diff --git a/ipalib/plugins/sudorule.py b/ipalib/plugins/sudorule.py
index ff7b756a..de7a7af3 100644
--- a/ipalib/plugins/sudorule.py
+++ b/ipalib/plugins/sudorule.py
@@ -40,6 +40,10 @@ FreeIPA provides a means to configure the various aspects of Sudo:
RunAsGroup: The group(s) whose gid rights Sudo will be invoked with.
Options: The various Sudoers Options that can modify Sudo's behavior.
+An order can be added to a sudorule to control the order in which they
+are evaluated (if the client supports it). This order is an integer and
+must be unique.
+
FreeIPA provides a designated binddn to use with Sudo located at:
uid=sudo,cn=sysaccounts,cn=etc,dc=example,dc=com
@@ -80,6 +84,7 @@ class sudorule(LDAPObject):
'memberallowcmd', 'memberdenycmd', 'ipasudoopt',
'ipasudorunas', 'ipasudorunasgroup',
'ipasudorunasusercategory', 'ipasudorunasgroupcategory',
+ 'sudoorder',
]
uuid_attribute = 'ipauniqueid'
rdn_attribute = 'ipauniqueid'
@@ -139,6 +144,13 @@ class sudorule(LDAPObject):
doc=_('RunAs Group category the rule applies to'),
values=(u'all', ),
),
+ Int('sudoorder?',
+ cli_name='order',
+ label=_('Sudo order'),
+ doc=_('integer to order the Sudo rules'),
+ default=0,
+ minvalue=0,
+ ),
Str('memberuser_user?',
label=_('Users'),
flags=['no_create', 'no_update', 'no_search'],
@@ -207,6 +219,25 @@ class sudorule(LDAPObject):
),
)
+ order_not_unique_msg = _(
+ 'order must be a unique value (%(order)d already used by %(rule)s)'
+ )
+
+ def check_order_uniqueness(self, *keys, **options):
+ if 'sudoorder' in options:
+ entries = self.methods.find(
+ sudoorder=options['sudoorder']
+ )['result']
+ if len(entries) > 0:
+ rule_name = entries[0]['cn'][0]
+ raise errors.ValidationError(
+ name='order',
+ error=self.order_not_unique_msg % {
+ 'order': options['sudoorder'],
+ 'rule': rule_name,
+ }
+ )
+
api.register(sudorule)
@@ -214,6 +245,7 @@ class sudorule_add(LDAPCreate):
__doc__ = _('Create new Sudo Rule.')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ self.obj.check_order_uniqueness(*keys, **options)
# Sudo Rules are enabled by default
entry_attrs['ipaenabledflag'] = 'TRUE'
return dn
@@ -236,6 +268,15 @@ class sudorule_mod(LDAPUpdate):
msg_summary = _('Modified Sudo Rule "%(value)s"')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ if 'sudoorder' in options:
+ new_order = options.get('sudoorder')
+ old_entry = self.api.Command.sudorule_show(keys[-1])['result']
+ if 'sudoorder' in old_entry:
+ old_order = int(old_entry['sudoorder'][0])
+ if old_order != new_order:
+ self.obj.check_order_uniqueness(*keys, **options)
+ else:
+ self.obj.check_order_uniqueness(*keys, **options)
try:
(_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
except errors.NotFound:
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 5b5b24ca..e549e13c 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -359,7 +359,7 @@ class DsInstance(service.Service):
"60basev2.ldif",
"60basev3.ldif",
"60ipadns.ldif",
- "60ipasudo.ldif"):
+ "65ipasudo.ldif"):
target_fname = schema_dirname(self.serverid) + schema_fname
shutil.copyfile(ipautil.SHARE_DIR + schema_fname, target_fname)
os.chmod(target_fname, 0440) # read access for dirsrv user/group
diff --git a/tests/test_xmlrpc/test_sudorule_plugin.py b/tests/test_xmlrpc/test_sudorule_plugin.py
index 4e283c20..bddf00c4 100644
--- a/tests/test_xmlrpc/test_sudorule_plugin.py
+++ b/tests/test_xmlrpc/test_sudorule_plugin.py
@@ -30,6 +30,7 @@ class test_sudorule(XMLRPC_test):
Test the `sudorule` plugin.
"""
rule_name = u'testing_sudorule1'
+ rule_name2 = u'testing_sudorule2'
rule_command = u'/usr/bin/testsudocmd1'
rule_desc = u'description'
rule_desc_mod = u'description modified'
@@ -38,8 +39,8 @@ class test_sudorule(XMLRPC_test):
test_external_user = u'external_test_user'
test_group = u'sudorule_test_group'
test_external_group = u'external_test_group'
- test_host = u'sudorule.test-host'
- test_external_host = u'external.test-host'
+ test_host = u'sudorule.testhost'
+ test_external_host = u'external.testhost'
test_hostgroup = u'sudorule_test_hostgroup'
test_sudoallowcmdgroup = u'sudorule_test_allowcmdgroup'
test_sudodenycmdgroup = u'sudorule_test_denycmdgroup'
@@ -625,8 +626,45 @@ class test_sudorule(XMLRPC_test):
api.Command['sudocmdgroup_del'](self.test_sudoallowcmdgroup)
api.Command['sudocmdgroup_del'](self.test_sudodenycmdgroup)
+ def test_l_sudorule_order(self):
+ """
+ Test that order uniqueness is maintained
+ """
+ api.Command['sudorule_mod'](self.rule_name, sudoorder=1)
+
+ api.Command['sudorule_add'](self.rule_name2)
+
+ # mod of rule that has no order and set a duplicate
+ try:
+ api.Command['sudorule_mod'](self.rule_name2, sudoorder=1)
+ except errors.ValidationError:
+ pass
+
+ # Remove the rule so we can re-add it
+ api.Command['sudorule_del'](self.rule_name2)
+
+ # add a new rule with a duplicate order
+ try:
+ api.Command['sudorule_add'](self.rule_name2, sudoorder=1)
+ except errors.ValidationError:
+ pass
+
+ # add a new rule with a unique order
+ api.Command['sudorule_add'](self.rule_name2, sudoorder=2)
+ try:
+ api.Command['sudorule_mod'](self.rule_name2, sudoorder=1)
+ except errors.ValidationError:
+ pass
+
+ # Try setting both to 0
+ api.Command['sudorule_mod'](self.rule_name2, sudoorder=0)
+ try:
+ api.Command['sudorule_mod'](self.rule_name, sudoorder=0)
+ except errors.ValidationError:
+ pass
+
- def test_l_sudorule_del(self):
+ def test_m_sudorule_del(self):
"""
Test deleting a Sudo rule using `xmlrpc.sudorule_del`.
"""
@@ -638,3 +676,4 @@ class test_sudorule(XMLRPC_test):
pass
else:
assert False
+ api.Command['sudorule_del'](self.rule_name2)