ac7d03
From bd2a0a8d363af6c8b1491314d5da5f3c146e4ce6 Mon Sep 17 00:00:00 2001
ac7d03
From: Stanislav Laznicka <slaznick@redhat.com>
ac7d03
Date: Mon, 27 Mar 2017 08:18:29 +0200
ac7d03
Subject: [PATCH] Reworked the renaming mechanism
ac7d03
ac7d03
The rename operation on *_mod commands was only allowed when
ac7d03
the primary key of an entry was also its RDN. With these changes,
ac7d03
it should be possible to rename the rest of the entries as well.
ac7d03
ac7d03
An attribute to the base LDAPObject was added to whitelist the
ac7d03
objects we want to allow to be renamed. It replaced an old
ac7d03
attribute rdn_is_primary_key which was used for the very same
ac7d03
purpose but the name was confusing because it was not set
ac7d03
correctly for certain objects.
ac7d03
ac7d03
https://pagure.io/freeipa/issue/2466
ac7d03
https://pagure.io/freeipa/issue/6784
ac7d03
ac7d03
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
ac7d03
Reviewed-By: Jan Cholasta <jcholast@redhat.com>
ac7d03
Reviewed-By: Martin Basti <mbasti@redhat.com>
ac7d03
---
ac7d03
 ipaserver/plugins/automount.py         |  2 +-
ac7d03
 ipaserver/plugins/baseldap.py          | 32 ++++++++++++++++++++------------
ac7d03
 ipaserver/plugins/baseuser.py          |  2 +-
ac7d03
 ipaserver/plugins/ca.py                |  2 +-
ac7d03
 ipaserver/plugins/dns.py               |  2 +-
ac7d03
 ipaserver/plugins/group.py             |  2 +-
ac7d03
 ipaserver/plugins/idviews.py           |  6 +++---
ac7d03
 ipaserver/plugins/otptoken.py          |  2 +-
ac7d03
 ipaserver/plugins/permission.py        |  2 +-
ac7d03
 ipaserver/plugins/privilege.py         |  2 +-
ac7d03
 ipaserver/plugins/radiusproxy.py       |  2 +-
ac7d03
 ipaserver/plugins/role.py              |  2 +-
ac7d03
 ipaserver/plugins/servicedelegation.py |  2 +-
ac7d03
 13 files changed, 34 insertions(+), 26 deletions(-)
ac7d03
ac7d03
diff --git a/ipaserver/plugins/automount.py b/ipaserver/plugins/automount.py
ac7d03
index c4cf2d6db876e13c78ecd73fc53bb356bf190e17..03f994c65832e7b6099739e951105c4b5a897391 100644
ac7d03
--- a/ipaserver/plugins/automount.py
ac7d03
+++ b/ipaserver/plugins/automount.py
ac7d03
@@ -456,7 +456,7 @@ class automountkey(LDAPObject):
ac7d03
     default_attributes = [
ac7d03
         'automountkey', 'automountinformation', 'description'
ac7d03
     ]
ac7d03
-    rdn_is_primary_key = True
ac7d03
+    allow_rename = True
ac7d03
     rdn_separator = ' '
ac7d03
 
ac7d03
     takes_params = (
ac7d03
diff --git a/ipaserver/plugins/baseldap.py b/ipaserver/plugins/baseldap.py
ac7d03
index 79ba7fc4a14f8105cda481e1599b2acbd8394e45..dbe3cbd28c85ebc3d9254e24e14c5701adc673ab 100644
ac7d03
--- a/ipaserver/plugins/baseldap.py
ac7d03
+++ b/ipaserver/plugins/baseldap.py
ac7d03
@@ -36,7 +36,7 @@ from ipalib.text import _
ac7d03
 from ipalib.util import json_serialize, validate_hostname
ac7d03
 from ipalib.capabilities import client_has_capability
ac7d03
 from ipalib.messages import add_message, SearchResultTruncated
ac7d03
-from ipapython.dn import DN
ac7d03
+from ipapython.dn import DN, RDN
ac7d03
 from ipapython.version import API_VERSION
ac7d03
 
ac7d03
 if six.PY3:
ac7d03
@@ -549,7 +549,7 @@ class LDAPObject(Object):
ac7d03
     rdn_attribute = ''
ac7d03
     uuid_attribute = ''
ac7d03
     attribute_members = {}
ac7d03
-    rdn_is_primary_key = False # Do we need RDN change to do a rename?
ac7d03
+    allow_rename = False
ac7d03
     password_attributes = []
ac7d03
     # Can bind as this entry (has userPassword or krbPrincipalKey)
ac7d03
     bindable = False
ac7d03
@@ -1384,7 +1384,7 @@ class LDAPUpdate(LDAPQuery, crud.Update):
ac7d03
     def get_options(self):
ac7d03
         for option in super(LDAPUpdate, self).get_options():
ac7d03
             yield option
ac7d03
-        if self.obj.rdn_is_primary_key:
ac7d03
+        if self.obj.allow_rename:
ac7d03
             yield self._get_rename_option()
ac7d03
 
ac7d03
     def execute(self, *keys, **options):
ac7d03
@@ -1419,15 +1419,19 @@ class LDAPUpdate(LDAPQuery, crud.Update):
ac7d03
         _check_limit_object_class(self.api.Backend.ldap2.schema.attribute_types(self.obj.disallow_object_classes), list(entry_attrs), allow_only=False)
ac7d03
 
ac7d03
         rdnupdate = False
ac7d03
-        try:
ac7d03
-            if self.obj.rdn_is_primary_key and 'rename' in options:
ac7d03
-                if not options['rename']:
ac7d03
-                    raise errors.ValidationError(name='rename', error=u'can\'t be empty')
ac7d03
-                entry_attrs[self.obj.primary_key.name] = options['rename']
ac7d03
-
ac7d03
-            if self.obj.rdn_is_primary_key and self.obj.primary_key.name in entry_attrs:
ac7d03
+        if 'rename' in options:
ac7d03
+            if not options['rename']:
ac7d03
+                raise errors.ValidationError(
ac7d03
+                    name='rename', error=u'can\'t be empty')
ac7d03
+            entry_attrs[self.obj.primary_key.name] = options['rename']
ac7d03
+
ac7d03
+        # if setattr was used to change the RDN, the primary_key.name is
ac7d03
+        # already in entry_attrs
ac7d03
+        if self.obj.allow_rename and self.obj.primary_key.name in entry_attrs:
ac7d03
+            # perform RDN change if the primary key is also RDN
ac7d03
+            if (RDN((self.obj.primary_key.name, keys[-1])) ==
ac7d03
+                    entry_attrs.dn[0]):
ac7d03
                 try:
ac7d03
-                    # RDN change
ac7d03
                     new_dn = DN((self.obj.primary_key.name,
ac7d03
                                  entry_attrs[self.obj.primary_key.name]),
ac7d03
                                 *entry_attrs.dn[1:])
ac7d03
@@ -1435,17 +1439,21 @@ class LDAPUpdate(LDAPQuery, crud.Update):
ac7d03
                         entry_attrs.dn,
ac7d03
                         new_dn)
ac7d03
 
ac7d03
-                    rdnkeys = keys[:-1] + (entry_attrs[self.obj.primary_key.name], )
ac7d03
+                    rdnkeys = (keys[:-1] +
ac7d03
+                               (entry_attrs[self.obj.primary_key.name], ))
ac7d03
                     entry_attrs.dn = self.obj.get_dn(*rdnkeys)
ac7d03
                     options['rdnupdate'] = True
ac7d03
                     rdnupdate = True
ac7d03
                 except errors.EmptyModlist:
ac7d03
                     # Attempt to rename to the current name, ignore
ac7d03
                     pass
ac7d03
+                except errors.NotFound:
ac7d03
+                    self.obj.handle_not_found(*keys)
ac7d03
                 finally:
ac7d03
                     # Delete the primary_key from entry_attrs either way
ac7d03
                     del entry_attrs[self.obj.primary_key.name]
ac7d03
 
ac7d03
+        try:
ac7d03
             # Exception callbacks will need to test for options['rdnupdate']
ac7d03
             # to decide what to do. An EmptyModlist in this context doesn't
ac7d03
             # mean an error occurred, just that there were no other updates to
ac7d03
diff --git a/ipaserver/plugins/baseuser.py b/ipaserver/plugins/baseuser.py
ac7d03
index 44adc76ec854dadbe0d8a4e8ca03e71c30df526c..bf24dbf542d3b481671dfe4e8cee14a2edcc26e0 100644
ac7d03
--- a/ipaserver/plugins/baseuser.py
ac7d03
+++ b/ipaserver/plugins/baseuser.py
ac7d03
@@ -164,7 +164,7 @@ class baseuser(LDAPObject):
ac7d03
         'memberof': ['group', 'netgroup', 'role', 'hbacrule', 'sudorule'],
ac7d03
         'memberofindirect': ['group', 'netgroup', 'role', 'hbacrule', 'sudorule'],
ac7d03
     }
ac7d03
-    rdn_is_primary_key = True
ac7d03
+    allow_rename = True
ac7d03
     bindable = True
ac7d03
     password_attributes = [('userpassword', 'has_password'),
ac7d03
                            ('krbprincipalkey', 'has_keytab')]
ac7d03
diff --git a/ipaserver/plugins/ca.py b/ipaserver/plugins/ca.py
ac7d03
index f774f78bd6d4ad236b37d06b8b267e8dd78f93b7..9bb163dffa645c1cbb10976e62cbd4a714139319 100644
ac7d03
--- a/ipaserver/plugins/ca.py
ac7d03
+++ b/ipaserver/plugins/ca.py
ac7d03
@@ -68,7 +68,7 @@ class ca(LDAPObject):
ac7d03
         'cn', 'description', 'ipacaid', 'ipacaissuerdn', 'ipacasubjectdn',
ac7d03
     ]
ac7d03
     rdn_attribute = 'cn'
ac7d03
-    rdn_is_primary_key = True
ac7d03
+    allow_rename = True
ac7d03
     label = _('Certificate Authorities')
ac7d03
     label_singular = _('Certificate Authority')
ac7d03
 
ac7d03
diff --git a/ipaserver/plugins/dns.py b/ipaserver/plugins/dns.py
ac7d03
index 7007928f3b4b2fd863077193671a03ae46119dc5..47ac963a0ae26fcaa81e70a8143bd7d0c172d20e 100644
ac7d03
--- a/ipaserver/plugins/dns.py
ac7d03
+++ b/ipaserver/plugins/dns.py
ac7d03
@@ -3000,7 +3000,7 @@ class dnsrecord(LDAPObject):
ac7d03
     possible_objectclasses = ['idnsTemplateObject']
ac7d03
     permission_filter_objectclasses = ['idnsrecord']
ac7d03
     default_attributes = ['idnsname'] + _record_attributes
ac7d03
-    rdn_is_primary_key = True
ac7d03
+    allow_rename = True
ac7d03
 
ac7d03
     label = _('DNS Resource Records')
ac7d03
     label_singular = _('DNS Resource Record')
ac7d03
diff --git a/ipaserver/plugins/group.py b/ipaserver/plugins/group.py
ac7d03
index 218da3c94d95bb399761acf9414182eff566c63b..1fb092d5f049e86f12681e5eb2397f98f1001697 100644
ac7d03
--- a/ipaserver/plugins/group.py
ac7d03
+++ b/ipaserver/plugins/group.py
ac7d03
@@ -173,7 +173,7 @@ class group(LDAPObject):
ac7d03
         'memberofindirect': ['group', 'netgroup', 'role', 'hbacrule',
ac7d03
         'sudorule'],
ac7d03
     }
ac7d03
-    rdn_is_primary_key = True
ac7d03
+    allow_rename = True
ac7d03
     managed_permissions = {
ac7d03
         'System: Read Groups': {
ac7d03
             'replaces_global_anonymous_aci': True,
ac7d03
diff --git a/ipaserver/plugins/idviews.py b/ipaserver/plugins/idviews.py
ac7d03
index 6d4ac75209ea08e3c2969d53e1ae5372c3a535ac..b5ee32cf138677874497e2f345c932c352e20054 100644
ac7d03
--- a/ipaserver/plugins/idviews.py
ac7d03
+++ b/ipaserver/plugins/idviews.py
ac7d03
@@ -97,7 +97,7 @@ class idview(LDAPObject):
ac7d03
     object_class = ['ipaIDView', 'top']
ac7d03
     possible_objectclasses = ['ipaNameResolutionData']
ac7d03
     default_attributes = ['cn', 'description', 'ipadomainresolutionorder']
ac7d03
-    rdn_is_primary_key = True
ac7d03
+    allow_rename = True
ac7d03
 
ac7d03
     label = _('ID Views')
ac7d03
     label_singular = _('ID View')
ac7d03
@@ -848,7 +848,7 @@ class idoverrideuser(baseidoverride):
ac7d03
 
ac7d03
     label = _('User ID overrides')
ac7d03
     label_singular = _('User ID override')
ac7d03
-    rdn_is_primary_key = True
ac7d03
+    allow_rename = True
ac7d03
 
ac7d03
     # ID user overrides are bindable because we map SASL GSSAPI
ac7d03
     # authentication of trusted users to ID user overrides in the
ac7d03
@@ -964,7 +964,7 @@ class idoverridegroup(baseidoverride):
ac7d03
 
ac7d03
     label = _('Group ID overrides')
ac7d03
     label_singular = _('Group ID override')
ac7d03
-    rdn_is_primary_key = True
ac7d03
+    allow_rename = True
ac7d03
 
ac7d03
     permission_filter_objectclasses = ['ipaGroupOverride']
ac7d03
     managed_permissions = {
ac7d03
diff --git a/ipaserver/plugins/otptoken.py b/ipaserver/plugins/otptoken.py
ac7d03
index 98ecbe58b84622d7937a7e6eff77c5e41624bf4f..c66f0980f0fc2ed49b4224be40a18ce528a6da7b 100644
ac7d03
--- a/ipaserver/plugins/otptoken.py
ac7d03
+++ b/ipaserver/plugins/otptoken.py
ac7d03
@@ -143,7 +143,7 @@ class otptoken(LDAPObject):
ac7d03
     relationships = {
ac7d03
         'managedby': ('Managed by', 'man_by_', 'not_man_by_'),
ac7d03
     }
ac7d03
-    rdn_is_primary_key = True
ac7d03
+    allow_rename = True
ac7d03
 
ac7d03
     label = _('OTP Tokens')
ac7d03
     label_singular = _('OTP Token')
ac7d03
diff --git a/ipaserver/plugins/permission.py b/ipaserver/plugins/permission.py
ac7d03
index dd2a0183e90ed6da9e55fb0590ea0bd81bf0bd67..977c6fe363c501f820aa82ae5b2ea00d8c78c7ae 100644
ac7d03
--- a/ipaserver/plugins/permission.py
ac7d03
+++ b/ipaserver/plugins/permission.py
ac7d03
@@ -188,7 +188,7 @@ class permission(baseldap.LDAPObject):
ac7d03
         'member': ['privilege'],
ac7d03
         'memberindirect': ['role'],
ac7d03
     }
ac7d03
-    rdn_is_primary_key = True
ac7d03
+    allow_rename = True
ac7d03
     managed_permissions = {
ac7d03
         'System: Read Permissions': {
ac7d03
             'replaces_global_anonymous_aci': True,
ac7d03
diff --git a/ipaserver/plugins/privilege.py b/ipaserver/plugins/privilege.py
ac7d03
index b3afbd289ac2e82d5569b5d5306be398a560413e..01d5396902d482eb5a9f21e7ece730a0a35157d6 100644
ac7d03
--- a/ipaserver/plugins/privilege.py
ac7d03
+++ b/ipaserver/plugins/privilege.py
ac7d03
@@ -101,7 +101,7 @@ class privilege(LDAPObject):
ac7d03
     reverse_members = {
ac7d03
         'member': ['permission'],
ac7d03
     }
ac7d03
-    rdn_is_primary_key = True
ac7d03
+    allow_rename = True
ac7d03
     managed_permissions = {
ac7d03
         'System: Read Privileges': {
ac7d03
             'replaces_global_anonymous_aci': True,
ac7d03
diff --git a/ipaserver/plugins/radiusproxy.py b/ipaserver/plugins/radiusproxy.py
ac7d03
index 3391b8aed77205fb1a586d5472d8cfdbc9fd1cd5..be77c62432066beec951e5f50afe689e1d6debce 100644
ac7d03
--- a/ipaserver/plugins/radiusproxy.py
ac7d03
+++ b/ipaserver/plugins/radiusproxy.py
ac7d03
@@ -101,7 +101,7 @@ class radiusproxy(LDAPObject):
ac7d03
         'ipatokenradiustimeout', 'ipatokenradiusretries', 'ipatokenusermapattribute'
ac7d03
     ]
ac7d03
     search_attributes = ['cn', 'description', 'ipatokenradiusserver']
ac7d03
-    rdn_is_primary_key = True
ac7d03
+    allow_rename = True
ac7d03
     label = _('RADIUS Servers')
ac7d03
     label_singular = _('RADIUS Server')
ac7d03
 
ac7d03
diff --git a/ipaserver/plugins/role.py b/ipaserver/plugins/role.py
ac7d03
index 5d0d1f8c657b8d840762135f5ff16db90fb4893f..e7f115c461a6a0421f9c43d0410daaf9d4307e76 100644
ac7d03
--- a/ipaserver/plugins/role.py
ac7d03
+++ b/ipaserver/plugins/role.py
ac7d03
@@ -92,7 +92,7 @@ class role(LDAPObject):
ac7d03
     reverse_members = {
ac7d03
         'member': ['privilege'],
ac7d03
     }
ac7d03
-    rdn_is_primary_key = True
ac7d03
+    allow_rename = True
ac7d03
     managed_permissions = {
ac7d03
         'System: Read Roles': {
ac7d03
             'replaces_global_anonymous_aci': True,
ac7d03
diff --git a/ipaserver/plugins/servicedelegation.py b/ipaserver/plugins/servicedelegation.py
ac7d03
index c8052e957cc5f8d24f6a8d0621ca93422052e35b..4f94924fa76691bcd6c6fc2cef9eb7fb30fce48c 100644
ac7d03
--- a/ipaserver/plugins/servicedelegation.py
ac7d03
+++ b/ipaserver/plugins/servicedelegation.py
ac7d03
@@ -138,7 +138,7 @@ class servicedelegation(LDAPObject):
ac7d03
         },
ac7d03
     }
ac7d03
 
ac7d03
-    rdn_is_primary_key = True
ac7d03
+    allow_rename = True
ac7d03
 
ac7d03
     takes_params = (
ac7d03
         Str(
ac7d03
-- 
ac7d03
2.12.1
ac7d03