URL: https://github.com/freeipa/freeipa/pull/617 Author: stlaz Title: #617: Allow renaming of sudo and HBAC rules Action: synchronized
To pull the PR as Git branch: git remote add ghfreeipa https://github.com/freeipa/freeipa git fetch ghfreeipa pull/617/head:pr617 git checkout pr617
From 862ec59543d57ffa073e9831e1ae5a17278595e1 Mon Sep 17 00:00:00 2001 From: Stanislav Laznicka <slazn...@redhat.com> Date: Mon, 27 Mar 2017 08:18:29 +0200 Subject: [PATCH 1/3] Reworked the renaming mechanism The rename operation on *_mod commands was only allowed when the primary key of an entry was also its RDN. With these changes, it should be possible to rename the rest of the entries as well. An attribute to the base LDAPObject was added to whitelist the objects we want to allow to be renamed. It replaced an old attribute rdn_is_primary_key which was used for the very same purpose but the name was confusing because it was not set correctly for certain objects. https://pagure.io/freeipa/issue/2466 https://pagure.io/freeipa/issue/6784 --- ipaserver/plugins/automount.py | 2 +- ipaserver/plugins/baseldap.py | 32 ++++++++++++++++++++------------ ipaserver/plugins/baseuser.py | 2 +- ipaserver/plugins/ca.py | 2 +- ipaserver/plugins/dns.py | 2 +- ipaserver/plugins/group.py | 2 +- ipaserver/plugins/idviews.py | 6 +++--- ipaserver/plugins/otptoken.py | 2 +- ipaserver/plugins/permission.py | 2 +- ipaserver/plugins/privilege.py | 2 +- ipaserver/plugins/radiusproxy.py | 2 +- ipaserver/plugins/role.py | 2 +- ipaserver/plugins/servicedelegation.py | 2 +- 13 files changed, 34 insertions(+), 26 deletions(-) diff --git a/ipaserver/plugins/automount.py b/ipaserver/plugins/automount.py index c4cf2d6..03f994c 100644 --- a/ipaserver/plugins/automount.py +++ b/ipaserver/plugins/automount.py @@ -456,7 +456,7 @@ class automountkey(LDAPObject): default_attributes = [ 'automountkey', 'automountinformation', 'description' ] - rdn_is_primary_key = True + allow_rename = True rdn_separator = ' ' takes_params = ( diff --git a/ipaserver/plugins/baseldap.py b/ipaserver/plugins/baseldap.py index 79ba7fc..dbe3cbd 100644 --- a/ipaserver/plugins/baseldap.py +++ b/ipaserver/plugins/baseldap.py @@ -36,7 +36,7 @@ from ipalib.util import json_serialize, validate_hostname from ipalib.capabilities import client_has_capability from ipalib.messages import add_message, SearchResultTruncated -from ipapython.dn import DN +from ipapython.dn import DN, RDN from ipapython.version import API_VERSION if six.PY3: @@ -549,7 +549,7 @@ class LDAPObject(Object): rdn_attribute = '' uuid_attribute = '' attribute_members = {} - rdn_is_primary_key = False # Do we need RDN change to do a rename? + allow_rename = False password_attributes = [] # Can bind as this entry (has userPassword or krbPrincipalKey) bindable = False @@ -1384,7 +1384,7 @@ def _get_rename_option(self): def get_options(self): for option in super(LDAPUpdate, self).get_options(): yield option - if self.obj.rdn_is_primary_key: + if self.obj.allow_rename: yield self._get_rename_option() def execute(self, *keys, **options): @@ -1419,15 +1419,19 @@ def execute(self, *keys, **options): _check_limit_object_class(self.api.Backend.ldap2.schema.attribute_types(self.obj.disallow_object_classes), list(entry_attrs), allow_only=False) rdnupdate = False - try: - if self.obj.rdn_is_primary_key and 'rename' in options: - if not options['rename']: - raise errors.ValidationError(name='rename', error=u'can\'t be empty') - entry_attrs[self.obj.primary_key.name] = options['rename'] - - if self.obj.rdn_is_primary_key and self.obj.primary_key.name in entry_attrs: + if 'rename' in options: + if not options['rename']: + raise errors.ValidationError( + name='rename', error=u'can\'t be empty') + entry_attrs[self.obj.primary_key.name] = options['rename'] + + # if setattr was used to change the RDN, the primary_key.name is + # already in entry_attrs + if self.obj.allow_rename and self.obj.primary_key.name in entry_attrs: + # perform RDN change if the primary key is also RDN + if (RDN((self.obj.primary_key.name, keys[-1])) == + entry_attrs.dn[0]): try: - # RDN change new_dn = DN((self.obj.primary_key.name, entry_attrs[self.obj.primary_key.name]), *entry_attrs.dn[1:]) @@ -1435,17 +1439,21 @@ def execute(self, *keys, **options): entry_attrs.dn, new_dn) - rdnkeys = keys[:-1] + (entry_attrs[self.obj.primary_key.name], ) + rdnkeys = (keys[:-1] + + (entry_attrs[self.obj.primary_key.name], )) entry_attrs.dn = self.obj.get_dn(*rdnkeys) options['rdnupdate'] = True rdnupdate = True except errors.EmptyModlist: # Attempt to rename to the current name, ignore pass + except errors.NotFound: + self.obj.handle_not_found(*keys) finally: # Delete the primary_key from entry_attrs either way del entry_attrs[self.obj.primary_key.name] + try: # Exception callbacks will need to test for options['rdnupdate'] # to decide what to do. An EmptyModlist in this context doesn't # mean an error occurred, just that there were no other updates to diff --git a/ipaserver/plugins/baseuser.py b/ipaserver/plugins/baseuser.py index 44adc76..bf24dbf 100644 --- a/ipaserver/plugins/baseuser.py +++ b/ipaserver/plugins/baseuser.py @@ -164,7 +164,7 @@ class baseuser(LDAPObject): 'memberof': ['group', 'netgroup', 'role', 'hbacrule', 'sudorule'], 'memberofindirect': ['group', 'netgroup', 'role', 'hbacrule', 'sudorule'], } - rdn_is_primary_key = True + allow_rename = True bindable = True password_attributes = [('userpassword', 'has_password'), ('krbprincipalkey', 'has_keytab')] diff --git a/ipaserver/plugins/ca.py b/ipaserver/plugins/ca.py index f774f78..9bb163d 100644 --- a/ipaserver/plugins/ca.py +++ b/ipaserver/plugins/ca.py @@ -68,7 +68,7 @@ class ca(LDAPObject): 'cn', 'description', 'ipacaid', 'ipacaissuerdn', 'ipacasubjectdn', ] rdn_attribute = 'cn' - rdn_is_primary_key = True + allow_rename = True label = _('Certificate Authorities') label_singular = _('Certificate Authority') diff --git a/ipaserver/plugins/dns.py b/ipaserver/plugins/dns.py index 7007928..47ac963 100644 --- a/ipaserver/plugins/dns.py +++ b/ipaserver/plugins/dns.py @@ -3000,7 +3000,7 @@ class dnsrecord(LDAPObject): possible_objectclasses = ['idnsTemplateObject'] permission_filter_objectclasses = ['idnsrecord'] default_attributes = ['idnsname'] + _record_attributes - rdn_is_primary_key = True + allow_rename = True label = _('DNS Resource Records') label_singular = _('DNS Resource Record') diff --git a/ipaserver/plugins/group.py b/ipaserver/plugins/group.py index 218da3c..1fb092d 100644 --- a/ipaserver/plugins/group.py +++ b/ipaserver/plugins/group.py @@ -173,7 +173,7 @@ class group(LDAPObject): 'memberofindirect': ['group', 'netgroup', 'role', 'hbacrule', 'sudorule'], } - rdn_is_primary_key = True + allow_rename = True managed_permissions = { 'System: Read Groups': { 'replaces_global_anonymous_aci': True, diff --git a/ipaserver/plugins/idviews.py b/ipaserver/plugins/idviews.py index 6d4ac75..b5ee32c 100644 --- a/ipaserver/plugins/idviews.py +++ b/ipaserver/plugins/idviews.py @@ -97,7 +97,7 @@ class idview(LDAPObject): object_class = ['ipaIDView', 'top'] possible_objectclasses = ['ipaNameResolutionData'] default_attributes = ['cn', 'description', 'ipadomainresolutionorder'] - rdn_is_primary_key = True + allow_rename = True label = _('ID Views') label_singular = _('ID View') @@ -848,7 +848,7 @@ class idoverrideuser(baseidoverride): label = _('User ID overrides') label_singular = _('User ID override') - rdn_is_primary_key = True + allow_rename = True # ID user overrides are bindable because we map SASL GSSAPI # authentication of trusted users to ID user overrides in the @@ -964,7 +964,7 @@ class idoverridegroup(baseidoverride): label = _('Group ID overrides') label_singular = _('Group ID override') - rdn_is_primary_key = True + allow_rename = True permission_filter_objectclasses = ['ipaGroupOverride'] managed_permissions = { diff --git a/ipaserver/plugins/otptoken.py b/ipaserver/plugins/otptoken.py index 98ecbe5..c66f098 100644 --- a/ipaserver/plugins/otptoken.py +++ b/ipaserver/plugins/otptoken.py @@ -143,7 +143,7 @@ class otptoken(LDAPObject): relationships = { 'managedby': ('Managed by', 'man_by_', 'not_man_by_'), } - rdn_is_primary_key = True + allow_rename = True label = _('OTP Tokens') label_singular = _('OTP Token') diff --git a/ipaserver/plugins/permission.py b/ipaserver/plugins/permission.py index dd2a018..977c6fe 100644 --- a/ipaserver/plugins/permission.py +++ b/ipaserver/plugins/permission.py @@ -188,7 +188,7 @@ class permission(baseldap.LDAPObject): 'member': ['privilege'], 'memberindirect': ['role'], } - rdn_is_primary_key = True + allow_rename = True managed_permissions = { 'System: Read Permissions': { 'replaces_global_anonymous_aci': True, diff --git a/ipaserver/plugins/privilege.py b/ipaserver/plugins/privilege.py index b3afbd2..01d5396 100644 --- a/ipaserver/plugins/privilege.py +++ b/ipaserver/plugins/privilege.py @@ -101,7 +101,7 @@ class privilege(LDAPObject): reverse_members = { 'member': ['permission'], } - rdn_is_primary_key = True + allow_rename = True managed_permissions = { 'System: Read Privileges': { 'replaces_global_anonymous_aci': True, diff --git a/ipaserver/plugins/radiusproxy.py b/ipaserver/plugins/radiusproxy.py index 3391b8a..be77c62 100644 --- a/ipaserver/plugins/radiusproxy.py +++ b/ipaserver/plugins/radiusproxy.py @@ -101,7 +101,7 @@ class radiusproxy(LDAPObject): 'ipatokenradiustimeout', 'ipatokenradiusretries', 'ipatokenusermapattribute' ] search_attributes = ['cn', 'description', 'ipatokenradiusserver'] - rdn_is_primary_key = True + allow_rename = True label = _('RADIUS Servers') label_singular = _('RADIUS Server') diff --git a/ipaserver/plugins/role.py b/ipaserver/plugins/role.py index 5d0d1f8..e7f115c 100644 --- a/ipaserver/plugins/role.py +++ b/ipaserver/plugins/role.py @@ -92,7 +92,7 @@ class role(LDAPObject): reverse_members = { 'member': ['privilege'], } - rdn_is_primary_key = True + allow_rename = True managed_permissions = { 'System: Read Roles': { 'replaces_global_anonymous_aci': True, diff --git a/ipaserver/plugins/servicedelegation.py b/ipaserver/plugins/servicedelegation.py index c8052e9..4f94924 100644 --- a/ipaserver/plugins/servicedelegation.py +++ b/ipaserver/plugins/servicedelegation.py @@ -138,7 +138,7 @@ class servicedelegation(LDAPObject): }, } - rdn_is_primary_key = True + allow_rename = True takes_params = ( Str( From b0c365e9b33f68363abbb981da096864e80cb58f Mon Sep 17 00:00:00 2001 From: Stanislav Laznicka <slazn...@redhat.com> Date: Mon, 27 Mar 2017 08:25:04 +0200 Subject: [PATCH 2/3] Allow renaming of the HBAC rule objects The recent changes allow HBAC rule objects to be renamed. https://pagure.io/freeipa/issue/6784 --- API.txt | 3 ++- VERSION.m4 | 4 ++-- ipaserver/plugins/hbacrule.py | 1 + ipatests/test_xmlrpc/test_hbac_plugin.py | 15 +++++++++++++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/API.txt b/API.txt index f0bd1b6..2a63c98 100644 --- a/API.txt +++ b/API.txt @@ -2163,7 +2163,7 @@ output: ListOfEntries('result') output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>]) output: Output('truncated', type=[<type 'bool'>]) command: hbacrule_mod/1 -args: 1,16,3 +args: 1,17,3 arg: Str('cn', cli_name='name') option: StrEnum('accessruletype?', autofill=False, cli_name='type', default=u'allow', values=[u'allow', u'deny']) option: Str('addattr*', cli_name='addattr') @@ -2175,6 +2175,7 @@ option: StrEnum('hostcategory?', autofill=False, cli_name='hostcat', values=[u'a option: Bool('ipaenabledflag?', autofill=False) option: Flag('no_members', autofill=True, default=False) option: Flag('raw', autofill=True, cli_name='raw', default=False) +option: Str('rename?', cli_name='rename') option: Flag('rights', autofill=True, default=False) option: StrEnum('servicecategory?', autofill=False, cli_name='servicecat', values=[u'all']) option: Str('setattr*', cli_name='setattr') diff --git a/VERSION.m4 b/VERSION.m4 index cfac2a9..75c0897 100644 --- a/VERSION.m4 +++ b/VERSION.m4 @@ -73,8 +73,8 @@ define(IPA_DATA_VERSION, 20100614120000) # # ######################################################## define(IPA_API_VERSION_MAJOR, 2) -define(IPA_API_VERSION_MINOR, 223) -# Last change: Add domain resolution order to ID views +define(IPA_API_VERSION_MINOR, 224) +# Last change: Add rename option to HBAC rule objects ######################################################## diff --git a/ipaserver/plugins/hbacrule.py b/ipaserver/plugins/hbacrule.py index 60e5e60..2495702 100644 --- a/ipaserver/plugins/hbacrule.py +++ b/ipaserver/plugins/hbacrule.py @@ -141,6 +141,7 @@ class hbacrule(LDAPObject): ] uuid_attribute = 'ipauniqueid' rdn_attribute = 'ipauniqueid' + allow_rename = True attribute_members = { 'memberuser': ['user', 'group'], 'memberhost': ['host', 'hostgroup'], diff --git a/ipatests/test_xmlrpc/test_hbac_plugin.py b/ipatests/test_xmlrpc/test_hbac_plugin.py index 75c15c5..b495fe3 100644 --- a/ipatests/test_xmlrpc/test_hbac_plugin.py +++ b/ipatests/test_xmlrpc/test_hbac_plugin.py @@ -34,6 +34,7 @@ class test_hbac(XMLRPC_test): Test the `hbacrule` plugin. """ rule_name = u'testing_rule1234' + rule_renamed = u'mega_testing_rule' rule_type = u'allow' rule_type_fail = u'value not allowed' rule_service = u'ssh' @@ -459,6 +460,20 @@ def test_n_hbacrule_links(self): assert_attr_equal(entry, 'cn', self.rule_name) assert_attr_equal(entry, 'memberservice_hbacsvc', self.test_service) + def test_o_hbacrule_rename(self): + """ + Test renaming an HBAC rule, rename it back afterwards + """ + api.Command['hbacrule_mod']( + self.rule_name, rename=self.rule_renamed + ) + entry = api.Command['hbacrule_show'](self.rule_renamed)['result'] + assert_attr_equal(entry, 'cn', self.rule_renamed) + # clean up by renaming the rule back + api.Command['hbacrule_mod']( + self.rule_renamed, rename=self.rule_name + ) + def test_y_hbacrule_zap_testing_data(self): """ Clear data for HBAC plugin testing. From ff2669bfbf1d8b3c14b88457d0da2886116ef97b Mon Sep 17 00:00:00 2001 From: Stanislav Laznicka <slazn...@redhat.com> Date: Mon, 27 Mar 2017 08:26:03 +0200 Subject: [PATCH 3/3] Allow renaming of the sudorule objects The recent changes allow the sudorule objects to be renamed. https://pagure.io/freeipa/issue/2466 --- API.txt | 3 ++- VERSION.m4 | 2 +- ipaserver/plugins/sudorule.py | 1 + ipatests/test_xmlrpc/test_sudorule_plugin.py | 14 ++++++++++++++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/API.txt b/API.txt index 2a63c98..7594157 100644 --- a/API.txt +++ b/API.txt @@ -5403,7 +5403,7 @@ output: ListOfEntries('result') output: Output('summary', type=[<type 'unicode'>, <type 'NoneType'>]) output: Output('truncated', type=[<type 'bool'>]) command: sudorule_mod/1 -args: 1,20,3 +args: 1,21,3 arg: Str('cn', cli_name='sudorule_name') option: Str('addattr*', cli_name='addattr') option: Flag('all', autofill=True, cli_name='all', default=False) @@ -5420,6 +5420,7 @@ option: StrEnum('ipasudorunasgroupcategory?', autofill=False, cli_name='runasgro option: StrEnum('ipasudorunasusercategory?', autofill=False, cli_name='runasusercat', values=[u'all']) option: Flag('no_members', autofill=True, default=False) option: Flag('raw', autofill=True, cli_name='raw', default=False) +option: Str('rename?', cli_name='rename') option: Flag('rights', autofill=True, default=False) option: Str('setattr*', cli_name='setattr') option: Int('sudoorder?', autofill=False, cli_name='order', default=0) diff --git a/VERSION.m4 b/VERSION.m4 index 75c0897..368f964 100644 --- a/VERSION.m4 +++ b/VERSION.m4 @@ -74,7 +74,7 @@ define(IPA_DATA_VERSION, 20100614120000) ######################################################## define(IPA_API_VERSION_MAJOR, 2) define(IPA_API_VERSION_MINOR, 224) -# Last change: Add rename option to HBAC rule objects +# Last change: Add rename option to sudorule objects ######################################################## diff --git a/ipaserver/plugins/sudorule.py b/ipaserver/plugins/sudorule.py index 9077107..28c3f21 100644 --- a/ipaserver/plugins/sudorule.py +++ b/ipaserver/plugins/sudorule.py @@ -145,6 +145,7 @@ class sudorule(LDAPObject): ] uuid_attribute = 'ipauniqueid' rdn_attribute = 'ipauniqueid' + allow_rename = True attribute_members = { 'memberuser': ['user', 'group'], 'memberhost': ['host', 'hostgroup'], diff --git a/ipatests/test_xmlrpc/test_sudorule_plugin.py b/ipatests/test_xmlrpc/test_sudorule_plugin.py index c37262a..75dbfbe 100644 --- a/ipatests/test_xmlrpc/test_sudorule_plugin.py +++ b/ipatests/test_xmlrpc/test_sudorule_plugin.py @@ -42,6 +42,7 @@ class test_sudorule(XMLRPC_test): """ rule_name = u'testing_sudorule1' rule_name2 = u'testing_sudorule2' + rule_renamed = u'testing_mega_sudorule' rule_command = u'/usr/bin/testsudocmd1' rule_desc = u'description' rule_desc_mod = u'description modified' @@ -782,6 +783,19 @@ def test_l_sudorule_order(self): api.Command['sudorule_mod'](self.rule_name, sudoorder=None) api.Command['sudorule_mod'](self.rule_name2, sudoorder=None) + def test_l_1_sudorule_rename(self): + """ + Test renaming an HBAC rule, rename it back afterwards + """ + api.Command['sudorule_mod']( + self.rule_name, rename=self.rule_renamed + ) + entry = api.Command['sudorule_show'](self.rule_renamed)['result'] + assert_attr_equal(entry, 'cn', self.rule_renamed) + # clean up by renaming the rule back + api.Command['sudorule_mod']( + self.rule_renamed, rename=self.rule_name + ) def test_m_sudorule_del(self): """
-- 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