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

Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Jan Cholasta <jcholast@redhat.com>
Reviewed-By: Martin Basti <mbasti@redhat.com>
This commit is contained in:
Stanislav Laznicka
2017-03-27 08:18:29 +02:00
committed by Pavel Vomacka
parent b7ae3363fd
commit 8e4408e678
13 changed files with 33 additions and 25 deletions

View File

@@ -456,7 +456,7 @@ class automountkey(LDAPObject):
default_attributes = [
'automountkey', 'automountinformation', 'description'
]
rdn_is_primary_key = True
allow_rename = True
rdn_separator = ' '
takes_params = (

View File

@@ -36,7 +36,7 @@ from ipalib.text import _
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 @@ class LDAPUpdate(LDAPQuery, crud.Update):
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 @@ class LDAPUpdate(LDAPQuery, crud.Update):
_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 'rename' in options:
if not options['rename']:
raise errors.ValidationError(name='rename', error=u'can\'t be empty')
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 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 @@ class LDAPUpdate(LDAPQuery, crud.Update):
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

View File

@@ -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')]

View File

@@ -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')

View File

@@ -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')

View File

@@ -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,

View File

@@ -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 = {

View File

@@ -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')

View File

@@ -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,

View File

@@ -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,

View File

@@ -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')

View File

@@ -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,

View File

@@ -138,7 +138,7 @@ class servicedelegation(LDAPObject):
},
}
rdn_is_primary_key = True
allow_rename = True
takes_params = (
Str(