From d55d8bfa7ed1d3617274c9f53974e7bf5209cc4e Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Thu, 1 Mar 2012 14:02:28 -0500 Subject: 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 --- API.txt | 9 ++++--- install/share/60ipasudo.ldif | 39 --------------------------- install/share/65ipasudo.ldif | 39 +++++++++++++++++++++++++++ install/share/Makefile.am | 2 +- install/updates/10-sudo.update | 2 ++ ipalib/plugins/sudorule.py | 41 ++++++++++++++++++++++++++++ ipaserver/install/dsinstance.py | 2 +- tests/test_xmlrpc/test_sudorule_plugin.py | 45 ++++++++++++++++++++++++++++--- 8 files changed, 132 insertions(+), 47 deletions(-) delete mode 100644 install/share/60ipasudo.ldif create mode 100644 install/share/65ipasudo.ldif diff --git a/API.txt b/API.txt index 88684dfad..9ba3ce4ac 100644 --- a/API.txt +++ b/API.txt @@ -2831,7 +2831,7 @@ output: Output('summary', (, ), None) output: Entry('result', , Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None)) output: Output('value', , 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', (, ), Gettext('A list output: Output('count', , None) output: Output('truncated', , 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/60ipasudo.ldif deleted file mode 100644 index 61c73c084..000000000 --- a/install/share/60ipasudo.ldif +++ /dev/null @@ -1,39 +0,0 @@ -dn: cn=schema -## -## IPA SUDO schema (added in IPA v2) -## -## Attributes: 2.16.840.1.113730.3.8.7.x -## ObjectClasses: 2.16.840.1.113730.3.8.8.x -## -## Attribute to store DN of an allowed SUDO command or a group of SUDO commands -attributetypes: (2.16.840.1.113730.3.8.7.1 NAME 'memberAllowCmd' DESC 'Reference to a command or group of commands that are allowed by the rule.' SUP distinguishedName EQUALITY distinguishedNameMatch ORDERING distinguishedNameMatch SUBSTR distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2' ) -## Attribute to store DN of a prohibited SUDO command or a group of SUDO commands -attributetypes: (2.16.840.1.113730.3.8.7.2 NAME 'memberDenyCmd' DESC 'Reference to a command or group of commands that are denied by the rule.' SUP distinguishedName EQUALITY distinguishedNameMatch ORDERING distinguishedNameMatch SUBSTR distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2' ) -## Attribute to store command category -attributeTypes: (2.16.840.1.113730.3.8.7.3 NAME 'cmdCategory' DESC 'Additional classification for commands' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) -## Attribute to store user not managed by the central server -attributetypes: (2.16.840.1.113730.3.8.7.4 NAME 'externalUser' DESC 'Multivalue string attribute that allows storing user names.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) -## Attribute to store sudo options -attributetypes: (2.16.840.1.113730.3.8.7.5 NAME 'ipaSudoOpt' DESC 'Options(s) followed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'IPA v2' ) -## Attribute to store the reference identity under which the command should be run -attributeTypes: (2.16.840.1.113730.3.8.7.6 NAME 'ipaSudoRunAs' DESC 'Reference to a user or group that the commands can be run as.' SUP memberUser X-ORIGIN 'IPA v2' ) -## Attribute to store a name of the user not managed by IPA. Command witll be executed under his identity. -attributeTypes: (2.16.840.1.113730.3.8.7.7 NAME 'ipaSudoRunAsExtUser' DESC 'Multivalue string attribute that allows storing user name the command can be run as' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) -## Attribute to express category of identities that the command can be run under -attributeTypes: (2.16.840.1.113730.3.8.7.8 NAME 'ipaSudoRunAsUserCategory' DESC 'Additional classification for users' SUP userCategory X-ORIGIN 'IPA v2' ) -## Attribute to store a reference to the "run as group" identitity -attributeTypes: (2.16.840.1.113730.3.8.7.9 NAME 'ipaSudoRunAsGroup' DESC 'Reference to group that the commands can be run as.' SUP memberUser X-ORIGIN 'IPA v2' ) -## Attribute to store a name of the "run as group" identitity if this group is not directly managed by IPA -attributeTypes: (2.16.840.1.113730.3.8.7.10 NAME 'ipaSudoRunAsExtGroup' DESC 'Multivalue string attribute that allows storing group name the command can be run as' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) -## Attribute to express category of group identities that the command can be run under -attributeTypes: (2.16.840.1.113730.3.8.7.11 NAME 'ipaSudoRunAsGroupCategory' DESC 'Additional classification for groups' SUP userCategory X-ORIGIN 'IPA v2' ) -## Attribute to store host mask -attributeTypes: (2.16.840.1.113730.3.8.7.12 NAME 'hostMask' DESC 'IP mask to identify a subnet.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) -## 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' ) -## 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 -objectClasses: (2.16.840.1.113730.3.8.8.3 NAME 'ipaSudoCmdGrp' DESC 'IPA object class to store groups of SUDO commands' SUP groupOfNames MUST ( ipaUniqueID ) STRUCTURAL X-ORIGIN 'IPA v2' ) diff --git a/install/share/65ipasudo.ldif b/install/share/65ipasudo.ldif new file mode 100644 index 000000000..7a85c8659 --- /dev/null +++ b/install/share/65ipasudo.ldif @@ -0,0 +1,39 @@ +dn: cn=schema +## +## IPA SUDO schema (added in IPA v2) +## +## Attributes: 2.16.840.1.113730.3.8.7.x +## ObjectClasses: 2.16.840.1.113730.3.8.8.x +## +## Attribute to store DN of an allowed SUDO command or a group of SUDO commands +attributetypes: (2.16.840.1.113730.3.8.7.1 NAME 'memberAllowCmd' DESC 'Reference to a command or group of commands that are allowed by the rule.' SUP distinguishedName EQUALITY distinguishedNameMatch ORDERING distinguishedNameMatch SUBSTR distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2' ) +## Attribute to store DN of a prohibited SUDO command or a group of SUDO commands +attributetypes: (2.16.840.1.113730.3.8.7.2 NAME 'memberDenyCmd' DESC 'Reference to a command or group of commands that are denied by the rule.' SUP distinguishedName EQUALITY distinguishedNameMatch ORDERING distinguishedNameMatch SUBSTR distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'IPA v2' ) +## Attribute to store command category +attributeTypes: (2.16.840.1.113730.3.8.7.3 NAME 'cmdCategory' DESC 'Additional classification for commands' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) +## Attribute to store user not managed by the central server +attributetypes: (2.16.840.1.113730.3.8.7.4 NAME 'externalUser' DESC 'Multivalue string attribute that allows storing user names.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) +## Attribute to store sudo options +attributetypes: (2.16.840.1.113730.3.8.7.5 NAME 'ipaSudoOpt' DESC 'Options(s) followed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'IPA v2' ) +## Attribute to store the reference identity under which the command should be run +attributeTypes: (2.16.840.1.113730.3.8.7.6 NAME 'ipaSudoRunAs' DESC 'Reference to a user or group that the commands can be run as.' SUP memberUser X-ORIGIN 'IPA v2' ) +## Attribute to store a name of the user not managed by IPA. Command witll be executed under his identity. +attributeTypes: (2.16.840.1.113730.3.8.7.7 NAME 'ipaSudoRunAsExtUser' DESC 'Multivalue string attribute that allows storing user name the command can be run as' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) +## Attribute to express category of identities that the command can be run under +attributeTypes: (2.16.840.1.113730.3.8.7.8 NAME 'ipaSudoRunAsUserCategory' DESC 'Additional classification for users' SUP userCategory X-ORIGIN 'IPA v2' ) +## Attribute to store a reference to the "run as group" identitity +attributeTypes: (2.16.840.1.113730.3.8.7.9 NAME 'ipaSudoRunAsGroup' DESC 'Reference to group that the commands can be run as.' SUP memberUser X-ORIGIN 'IPA v2' ) +## Attribute to store a name of the "run as group" identitity if this group is not directly managed by IPA +attributeTypes: (2.16.840.1.113730.3.8.7.10 NAME 'ipaSudoRunAsExtGroup' DESC 'Multivalue string attribute that allows storing group name the command can be run as' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) +## Attribute to express category of group identities that the command can be run under +attributeTypes: (2.16.840.1.113730.3.8.7.11 NAME 'ipaSudoRunAsGroupCategory' DESC 'Additional classification for groups' SUP userCategory X-ORIGIN 'IPA v2' ) +## Attribute to store host mask +attributeTypes: (2.16.840.1.113730.3.8.7.12 NAME 'hostMask' DESC 'IP mask to identify a subnet.' EQUALITY caseIgnoreMatch ORDERING caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'IPA v2' ) +## 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 $ 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 +objectClasses: (2.16.840.1.113730.3.8.8.3 NAME 'ipaSudoCmdGrp' DESC 'IPA object class to store groups of SUDO commands' SUP groupOfNames MUST ( ipaUniqueID ) STRUCTURAL X-ORIGIN 'IPA v2' ) diff --git a/install/share/Makefile.am b/install/share/Makefile.am index eefa35343..243fc2a11 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 88bdc3ce1..a12da0043 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 ff7b756a3..de7a7af37 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 5b5b24caa..e549e13cc 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 4e283c208..bddf00c4f 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) -- cgit