Hi,
these patches implement attribute name case preservation in LDAPEntry.
Apply on top of Petr Viktorin's LDAP code refactoring patchset (up to
part 5).
Honza
--
Jan Cholasta
>From 8778f668591e28d78741df55dc2bca98917073e5 Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jchol...@redhat.com>
Date: Thu, 31 Jan 2013 11:19:13 +0100
Subject: [PATCH 1/4] Use the dn attribute of LDAPEntry to set/get DNs of
entries.
Convert all code that uses the 'dn' key of LDAPEntry for this to use the dn
attribute instead.
---
install/tools/ipa-compliance | 10 +++----
install/tools/ipa-replica-install | 2 +-
ipalib/plugins/automember.py | 9 ++++--
ipalib/plugins/baseldap.py | 58 +++++++++++++++++++++++++++------------
ipalib/plugins/krbtpolicy.py | 6 ++--
ipalib/plugins/permission.py | 6 ++--
ipalib/plugins/sudorule.py | 8 ++++--
ipalib/plugins/trust.py | 2 +-
ipalib/plugins/user.py | 9 ++----
ipaserver/ipaldap.py | 4 +--
ipaserver/plugins/ldap2.py | 2 --
11 files changed, 73 insertions(+), 43 deletions(-)
diff --git a/install/tools/ipa-compliance b/install/tools/ipa-compliance
index c82e415..9b34350 100644
--- a/install/tools/ipa-compliance
+++ b/install/tools/ipa-compliance
@@ -116,7 +116,7 @@ def check_compliance(tmpdir, debug=False):
hostcount = 0
# Get the hosts first
try:
- (entries, truncated) = conn.find_entries('(krblastpwdchange=*)', ['dn'],
+ (entries, truncated) = conn.find_entries('(krblastpwdchange=*)', [],
DN(api.env.container_host, api.env.basedn),
conn.SCOPE_ONELEVEL,
size_limit = -1)
@@ -136,10 +136,10 @@ def check_compliance(tmpdir, debug=False):
available = 0
try:
(entries, truncated) = conn.find_entries('(objectclass=ipaentitlement)',
- ['dn', 'userCertificate'],
- DN(api.env.container_entitlements, api.env.basedn),
- conn.SCOPE_ONELEVEL,
- size_limit = -1)
+ ['userCertificate'],
+ DN(api.env.container_entitlements, api.env.basedn),
+ conn.SCOPE_ONELEVEL,
+ size_limit = -1)
for entry in entries:
(dn, attrs) = entry
diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install
index 13c3260..846122d 100755
--- a/install/tools/ipa-replica-install
+++ b/install/tools/ipa-replica-install
@@ -572,7 +572,7 @@ def main():
config.dirman_password)
found = False
try:
- entry = conn.find_entries(u'fqdn=%s' % host, ['dn', 'fqdn'], DN(api.env.container_host, api.env.basedn))
+ entry = conn.find_entries(u'fqdn=%s' % host, ['fqdn'], DN(api.env.container_host, api.env.basedn))
print "The host %s already exists on the master server.\nYou should remove it before proceeding:" % host
print " %% ipa host-del %s" % host
found = True
diff --git a/ipalib/plugins/automember.py b/ipalib/plugins/automember.py
index af39f6a..520f8a0 100644
--- a/ipalib/plugins/automember.py
+++ b/ipalib/plugins/automember.py
@@ -316,10 +316,12 @@ class automember_add_condition(LDAPUpdate):
except errors.NotFound:
failed['failed'][attr].append(regex)
+ entry_attrs = entry_to_dict(entry_attrs, **options)
+
# Set failed and completed to they can be harvested in the execute super
setattr(context, 'failed', failed)
setattr(context, 'completed', completed)
- setattr(context, 'entry_attrs', dict(entry_attrs))
+ setattr(context, 'entry_attrs', entry_attrs)
# Make sure to returned the failed results if there is nothing to remove
if completed == 0:
@@ -406,10 +408,13 @@ class automember_remove_condition(LDAPUpdate):
else:
failed['failed'][attr].append(regex)
entry_attrs[attr] = old_entry
+
+ entry_attrs = entry_to_dict(entry_attrs, **options)
+
# Set failed and completed to they can be harvested in the execute super
setattr(context, 'failed', failed)
setattr(context, 'completed', completed)
- setattr(context, 'entry_attrs', dict(entry_attrs))
+ setattr(context, 'entry_attrs', entry_attrs)
# Make sure to returned the failed results if there is nothing to remove
if completed == 0:
diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py
index 44751e1..74e2384 100644
--- a/ipalib/plugins/baseldap.py
+++ b/ipalib/plugins/baseldap.py
@@ -229,6 +229,12 @@ def entry_from_entry(entry, newentry):
for e in newentry.keys():
entry[e] = newentry[e]
+def entry_to_dict(entry, **options):
+ result = dict(entry)
+ if options.get('all', False):
+ result['dn'] = entry.dn
+ return result
+
def wait_for_value(ldap, dn, attr, value):
"""
389-ds postoperation plugins are executed after the data has been
@@ -978,6 +984,7 @@ class LDAPCreate(BaseLDAPCommand, crud.Create):
ldap = self.obj.backend
entry_attrs = self.args_options_2_entry(*keys, **options)
+ entry_attrs = ldap.make_entry(DN(), entry_attrs)
self.process_attr_options(entry_attrs, None, keys, options)
@@ -1063,13 +1070,15 @@ class LDAPCreate(BaseLDAPCommand, crud.Create):
for callback in self.get_callbacks('post'):
dn = callback(self, ldap, dn, entry_attrs, *keys, **options)
+ self.obj.convert_attribute_members(entry_attrs, *keys, **options)
+
assert isinstance(dn, DN)
+ entry_attrs = entry_to_dict(entry_attrs, **options)
entry_attrs['dn'] = dn
- self.obj.convert_attribute_members(entry_attrs, *keys, **options)
if self.obj.primary_key and keys[-1] is not None:
- return dict(result=dict(entry_attrs), value=keys[-1])
- return dict(result=dict(entry_attrs), value=u'')
+ return dict(result=entry_attrs, value=keys[-1])
+ return dict(result=entry_attrs, value=u'')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
assert isinstance(dn, DN)
@@ -1190,11 +1199,14 @@ class LDAPRetrieve(LDAPQuery):
assert isinstance(dn, DN)
self.obj.convert_attribute_members(entry_attrs, *keys, **options)
+
assert isinstance(dn, DN)
+ entry_attrs = entry_to_dict(entry_attrs, **options)
entry_attrs['dn'] = dn
+
if self.obj.primary_key and keys[-1] is not None:
- return dict(result=dict(entry_attrs), value=keys[-1])
- return dict(result=dict(entry_attrs), value=u'')
+ return dict(result=entry_attrs, value=keys[-1])
+ return dict(result=entry_attrs, value=u'')
def pre_callback(self, ldap, dn, attrs_list, *keys, **options):
assert isinstance(dn, DN)
@@ -1253,6 +1265,7 @@ class LDAPUpdate(LDAPQuery, crud.Update):
assert isinstance(dn, DN)
entry_attrs = self.args_options_2_entry(**options)
+ entry_attrs = ldap.make_entry(dn, entry_attrs)
self.process_attr_options(entry_attrs, dn, keys, options)
@@ -1321,9 +1334,12 @@ class LDAPUpdate(LDAPQuery, crud.Update):
assert isinstance(dn, DN)
self.obj.convert_attribute_members(entry_attrs, *keys, **options)
+
+ entry_attrs = entry_to_dict(entry_attrs, **options)
+
if self.obj.primary_key and keys[-1] is not None:
- return dict(result=dict(entry_attrs), value=keys[-1])
- return dict(result=dict(entry_attrs), value=u'')
+ return dict(result=entry_attrs, value=keys[-1])
+ return dict(result=entry_attrs, value=u'')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
assert isinstance(dn, DN)
@@ -1544,13 +1560,16 @@ class LDAPAddMember(LDAPModMember):
**options)
assert isinstance(dn, DN)
+ self.obj.convert_attribute_members(entry_attrs, *keys, **options)
+
assert isinstance(dn, DN)
+ entry_attrs = entry_to_dict(entry_attrs, **options)
entry_attrs['dn'] = dn
- self.obj.convert_attribute_members(entry_attrs, *keys, **options)
+
return dict(
completed=completed,
failed=failed,
- result=dict(entry_attrs),
+ result=entry_attrs,
)
def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
@@ -1642,14 +1661,16 @@ class LDAPRemoveMember(LDAPModMember):
**options)
assert isinstance(dn, DN)
+ self.obj.convert_attribute_members(entry_attrs, *keys, **options)
+
assert isinstance(dn, DN)
+ entry_attrs = entry_to_dict(entry_attrs, **options)
entry_attrs['dn'] = dn
- self.obj.convert_attribute_members(entry_attrs, *keys, **options)
return dict(
completed=completed,
failed=failed,
- result=dict(entry_attrs),
+ result=entry_attrs,
)
def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
@@ -1856,10 +1877,9 @@ class LDAPSearch(BaseLDAPCommand, crud.Search):
for e in entries:
self.obj.convert_attribute_members(e[1], *args, **options)
- for e in entries:
- assert isinstance(e[0], DN)
- e[1]['dn'] = e[0]
- entries = [dict(e) for (dn, e) in entries]
+ for (i, e) in enumerate(entries):
+ entries[i] = entry_to_dict(e, **options)
+ entries[i]['dn'] = e.dn
return dict(
result=entries,
@@ -1994,11 +2014,13 @@ class LDAPAddReverseMember(LDAPModReverseMember):
assert isinstance(dn, DN)
assert isinstance(dn, DN)
+ entry_attrs = entry_to_dict(entry_attrs, **options)
entry_attrs['dn'] = dn
+
return dict(
completed=completed,
failed=failed,
- result=dict(entry_attrs),
+ result=entry_attrs,
)
def pre_callback(self, ldap, dn, *keys, **options):
@@ -2094,11 +2116,13 @@ class LDAPRemoveReverseMember(LDAPModReverseMember):
assert isinstance(dn, DN)
assert isinstance(dn, DN)
+ entry_attrs = entry_to_dict(entry_attrs, **options)
entry_attrs['dn'] = dn
+
return dict(
completed=completed,
failed=failed,
- result=dict(entry_attrs),
+ result=entry_attrs,
)
def pre_callback(self, ldap, dn, *keys, **options):
diff --git a/ipalib/plugins/krbtpolicy.py b/ipalib/plugins/krbtpolicy.py
index 07e3148..976f92b 100644
--- a/ipalib/plugins/krbtpolicy.py
+++ b/ipalib/plugins/krbtpolicy.py
@@ -176,8 +176,10 @@ class krbtpolicy_reset(LDAPQuery):
dn = self.obj.get_dn(None)
(dn, entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
+ entry_attrs = entry_to_dict(entry_attrs, **options)
+
if keys[-1] is not None:
- return dict(result=dict(entry_attrs), value=keys[-1])
- return dict(result=dict(entry_attrs), value=u'')
+ return dict(result=entry_attrs, value=keys[-1])
+ return dict(result=entry_attrs, value=u'')
api.register(krbtpolicy_reset)
diff --git a/ipalib/plugins/permission.py b/ipalib/plugins/permission.py
index 1fbf9e0..91bea32 100644
--- a/ipalib/plugins/permission.py
+++ b/ipalib/plugins/permission.py
@@ -474,10 +474,10 @@ class permission_find(LDAPSearch):
dn = permission['dn']
del permission['dn']
if pkey_only:
- new_entry = (dn, {self.obj.primary_key.name: \
- permission[self.obj.primary_key.name]})
+ pk = self.obj.primary_key.name
+ new_entry = ldap.make_entry(dn, {pk: permission[pk]})
else:
- new_entry = (dn, permission)
+ new_entry = ldap.make_entry(dn, permission)
if (dn, permission) not in entries:
if len(entries) < max_entries:
diff --git a/ipalib/plugins/sudorule.py b/ipalib/plugins/sudorule.py
index 907c01b..f6a0257 100644
--- a/ipalib/plugins/sudorule.py
+++ b/ipalib/plugins/sudorule.py
@@ -642,7 +642,9 @@ class sudorule_add_option(LDAPQuery):
dn, attrs_list, normalize=self.obj.normalize_dn
)
- return dict(result=dict(entry_attrs))
+ entry_attrs = entry_to_dict(entry_attrs, **options)
+
+ return dict(result=entry_attrs)
def output_for_cli(self, textui, result, cn, **options):
textui.print_dashed(_('Added option "%(option)s" to Sudo Rule "%(rule)s"') % \
@@ -697,7 +699,9 @@ class sudorule_remove_option(LDAPQuery):
dn, attrs_list, normalize=self.obj.normalize_dn
)
- return dict(result=dict(entry_attrs))
+ entry_attrs = entry_to_dict(entry_attrs, **options)
+
+ return dict(result=entry_attrs)
def output_for_cli(self, textui, result, cn, **options):
textui.print_dashed(_('Removed option "%(option)s" from Sudo Rule "%(rule)s"') % \
diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py
index a33a7ce..6f7e1aa 100644
--- a/ipalib/plugins/trust.py
+++ b/ipalib/plugins/trust.py
@@ -255,7 +255,7 @@ sides.
base_dn = DN(api.env.container_trusts, api.env.basedn),
filter = trust_filter)
- result['result'] = dict(trusts[0][1])
+ result['result'] = entry_to_dict(trusts[0][1], **options)
result['result']['trusttype'] = [trust_type_string(result['result']['ipanttrusttype'][0])]
result['result']['trustdirection'] = [trust_direction_string(result['result']['ipanttrustdirection'][0])]
result['result']['truststatus'] = [trust_status_string(result['verified'])]
diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py
index 80bdc39..979ade1 100644
--- a/ipalib/plugins/user.py
+++ b/ipalib/plugins/user.py
@@ -838,15 +838,14 @@ class user_status(LDAPQuery):
other_ldap.connect(ccache=os.environ['KRB5CCNAME'])
except Exception, e:
self.error("user_status: Connecting to %s failed with %s" % (host, str(e)))
- newresult = dict()
- newresult['dn'] = dn
+ newresult = ldap.make_entry(dn)
newresult['server'] = _("%(host)s failed: %(error)s") % dict(host=host, error=str(e))
entries.append(newresult)
count += 1
continue
try:
entry = other_ldap.get_entry(dn, attr_list)
- newresult = dict()
+ newresult = ldap.make_entry(dn)
for attr in ['krblastsuccessfulauth', 'krblastfailedauth']:
newresult[attr] = entry[1].get(attr, [u'N/A'])
newresult['krbloginfailedcount'] = entry[1].get('krbloginfailedcount', u'0')
@@ -860,7 +859,6 @@ class user_status(LDAPQuery):
except Exception, e:
self.debug("time conversion failed with %s" % str(e))
pass
- newresult['dn'] = dn
newresult['server'] = host
if options.get('raw', False):
time_format = '%Y%m%d%H%M%SZ'
@@ -876,8 +874,7 @@ class user_status(LDAPQuery):
self.obj.handle_not_found(*keys)
except Exception, e:
self.error("user_status: Retrieving status for %s failed with %s" % (dn, str(e)))
- newresult = dict()
- newresult['dn'] = dn
+ newresult = ldap.make_entry(dn)
newresult['server'] = _("%(host)s failed") % dict(host=host)
entries.append(newresult)
count += 1
diff --git a/ipaserver/ipaldap.py b/ipaserver/ipaldap.py
index 43e4d8b..20c11b4 100644
--- a/ipaserver/ipaldap.py
+++ b/ipaserver/ipaldap.py
@@ -1234,7 +1234,7 @@ class LDAPClient(object):
return ([], [])
search_entry_dn = ldap.filter.escape_filter_chars(str(entry_dn))
- attr_list = ["dn", "memberof"]
+ attr_list = ["memberof"]
searchfilter = "(|(member=%s)(memberhost=%s)(memberuser=%s))" % (
search_entry_dn, search_entry_dn, search_entry_dn)
@@ -1348,7 +1348,7 @@ class LDAPClient(object):
return entries
dn, group = self.get_entry(
- group_dn, ['dn', 'member'],
+ group_dn, ['member'],
size_limit=size_limit, time_limit=time_limit)
real_members = group.get('member', [])
diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py
index c3d7d33..6f6c206 100644
--- a/ipaserver/plugins/ldap2.py
+++ b/ipaserver/plugins/ldap2.py
@@ -469,7 +469,6 @@ class ldap2(LDAPClient, CrudBackend):
assert isinstance(dn, DN)
(dn, entry_attrs) = self.get_entry(dn, attrs_list)
- entry_attrs['dn'] = dn
return entry_attrs
def create(self, **kw):
@@ -545,7 +544,6 @@ class ldap2(LDAPClient, CrudBackend):
filter, attrs_list, base_dn, scope
)
for (dn, entry_attrs) in entries:
- entry_attrs['dn'] = [dn]
output.append(entry_attrs)
if truncated:
--
1.8.1
>From 15acfcdaa1f2c37a7e10ee165e89f6d13ee3d7ea Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jchol...@redhat.com>
Date: Thu, 31 Jan 2013 11:56:00 +0100
Subject: [PATCH 2/4] Preserve case of attribute names in LDAPEntry.
---
ipalib/plugins/baseldap.py | 5 ++-
ipalib/plugins/cert.py | 6 +--
ipalib/plugins/pwpolicy.py | 6 +--
ipaserver/ipaldap.py | 102 +++++++++++++++++++++++++++++++++------------
4 files changed, 86 insertions(+), 33 deletions(-)
diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py
index 74e2384..a0708d9 100644
--- a/ipalib/plugins/baseldap.py
+++ b/ipalib/plugins/baseldap.py
@@ -230,7 +230,10 @@ def entry_from_entry(entry, newentry):
entry[e] = newentry[e]
def entry_to_dict(entry, **options):
- result = dict(entry)
+ if options.get('raw', False):
+ result = dict(entry)
+ else:
+ result = dict((k.lower(), v) for (k, v) in entry.iteritems())
if options.get('all', False):
result['dn'] = entry.dn
return result
diff --git a/ipalib/plugins/cert.py b/ipalib/plugins/cert.py
index 3aa0162..52c242d 100644
--- a/ipalib/plugins/cert.py
+++ b/ipalib/plugins/cert.py
@@ -313,11 +313,11 @@ class cert_request(VirtualCommand):
# going to add it
try:
if not principal.startswith('host/'):
- service = api.Command['service_show'](principal, all=True, raw=True)['result']
+ service = api.Command['service_show'](principal, all=True)['result']
dn = service['dn']
else:
hostname = get_host_from_principal(principal)
- service = api.Command['host_show'](hostname, all=True, raw=True)['result']
+ service = api.Command['host_show'](hostname, all=True)['result']
dn = service['dn']
except errors.NotFound, e:
if not add:
@@ -342,7 +342,7 @@ class cert_request(VirtualCommand):
for name in subjectaltname:
name = unicode(name)
try:
- hostentry = api.Command['host_show'](name, all=True, raw=True)['result']
+ hostentry = api.Command['host_show'](name, all=True)['result']
hostdn = hostentry['dn']
except errors.NotFound:
# We don't want to issue any certificates referencing
diff --git a/ipalib/plugins/pwpolicy.py b/ipalib/plugins/pwpolicy.py
index 5ae07c4..6c8ad8d 100644
--- a/ipalib/plugins/pwpolicy.py
+++ b/ipalib/plugins/pwpolicy.py
@@ -305,12 +305,12 @@ class pwpolicy(LDAPObject):
existing_entry = {}
if not add: # then read existing entry
existing_entry = self.api.Command.pwpolicy_show(keys[-1],
- all=True, raw=True,
+ all=True,
)['result']
if minlife is None and 'krbminpwdlife' in existing_entry:
- minlife = int(existing_entry['krbminpwdlife'][0])
+ minlife = int(existing_entry['krbminpwdlife'][0]) * 3600
if maxlife is None and 'krbmaxpwdlife' in existing_entry:
- maxlife = int(existing_entry['krbmaxpwdlife'][0])
+ maxlife = int(existing_entry['krbmaxpwdlife'][0]) * 86400
if maxlife is not None and minlife is not None:
if minlife > maxlife:
diff --git a/ipaserver/ipaldap.py b/ipaserver/ipaldap.py
index 20c11b4..6268ac0 100644
--- a/ipaserver/ipaldap.py
+++ b/ipaserver/ipaldap.py
@@ -578,7 +578,7 @@ class IPASimpleLDAPObject(object):
# r[0] == r.dn
# r[1] == r.data
class LDAPEntry(dict):
- __slots__ = ('_dn', '_orig')
+ __slots__ = ('_dn', '_names', '_orig')
def __init__(self, _dn=None, _obj=None, **kwargs):
super(LDAPEntry, self).__init__()
@@ -599,6 +599,7 @@ class LDAPEntry(dict):
self._dn = _dn
self._orig = orig
+ self._names = CIDict()
if orig is None:
self.commit()
@@ -625,23 +626,9 @@ class LDAPEntry(dict):
# FIXME: for backwards compatibility only
return self._orig
- def _attr_name(self, name):
- if not isinstance(name, basestring):
- raise TypeError(
- "attribute name must be unicode or str, got %s object %r" % (
- name.__class__.__name__, name))
- if isinstance(name, str):
- name = name.decode('ascii')
- return name.lower()
-
- def _init_iter(self, _obj, **kwargs):
- _obj = dict(_obj, **kwargs)
- for (k, v) in _obj.iteritems():
- yield (self._attr_name(k), v)
-
def __repr__(self):
- dict_repr = super(LDAPEntry, self).__repr__()
- return '%s(%s, %s)' % (type(self).__name__, repr(self._dn), dict_repr)
+ return '%s(%r, %s)' % (type(self).__name__, self._dn,
+ super(LDAPEntry, self).__repr__())
def copy(self):
return LDAPEntry(self)
@@ -650,14 +637,48 @@ class LDAPEntry(dict):
self._orig = self
self._orig = deepcopy(self)
+ def _attr_name(self, name):
+ if not isinstance(name, (unicode, str)):
+ raise TypeError(
+ "attribute name must be unicode or str, got %s object %r" % (
+ name.__class__.__name__, name))
+
+ if isinstance(name, str):
+ name = name.decode('utf-8')
+
+ return name
+
def __setitem__(self, name, value):
- super(LDAPEntry, self).__setitem__(self._attr_name(name), value)
+ name = self._attr_name(name)
+
+ if name in self._names:
+ oldname = self._names[name]
+
+ if oldname != name:
+ for (altname, keyname) in self._names.iteritems():
+ if keyname == oldname:
+ self._names[altname] = name
+
+ super(LDAPEntry, self).__delitem__(oldname)
+ else:
+ self._names[name] = name
+
+ super(LDAPEntry, self).__setitem__(name, value)
def setdefault(self, name, default):
- return super(LDAPEntry, self).setdefault(self._attr_name(name), default)
+ if name not in self:
+ self[name] = default
+ return self[name]
def update(self, _obj={}, **kwargs):
- super(LDAPEntry, self).update(self._init_iter(_obj, **kwargs))
+ _obj = dict(_obj, **kwargs)
+ for (name, value) in _obj.iteritems():
+ self[name] = value
+
+ def _get_attr_name(self, name):
+ name = self._attr_name(name)
+ name = self._names[name]
+ return name
def __getitem__(self, name):
# for python-ldap tuple compatibility
@@ -666,10 +687,24 @@ class LDAPEntry(dict):
elif name == 1:
return self
- return super(LDAPEntry, self).__getitem__(self._attr_name(name))
+ return super(LDAPEntry, self).__getitem__(self._get_attr_name(name))
def get(self, name, default=None):
- return super(LDAPEntry, self).get(self._attr_name(name), default)
+ try:
+ name = self._get_attr_name(name)
+ except KeyError:
+ return default
+
+ return super(LDAPEntry, self).get(name, default)
+
+ def _del_attr_name(self, name):
+ name = self._get_attr_name(name)
+
+ for (altname, keyname) in self._names.items():
+ if keyname == name:
+ del self._names[altname]
+
+ return name
def get_single(self, name, default=_missing):
"""Return a single attribute value
@@ -688,16 +723,31 @@ class LDAPEntry(dict):
return values[0]
def __delitem__(self, name):
- super(LDAPEntry, self).__delitem__(self._attr_name(name))
+ super(LDAPEntry, self).__delitem__(self._del_attr_name(name))
def pop(self, name, *default):
- return super(LDAPEntry, self).pop(self._attr_name(name), *default)
+ try:
+ name = self._del_attr_name(name)
+ except KeyError:
+ if not default:
+ raise
+
+ return super(LDAPEntry, self).pop(name, *default)
+
+ def popitem(self):
+ name, value = super(LDAPEntry, self).popitem()
+ self._del_attr_name(name)
+ return (name, value)
+
+ def clear(self):
+ super(LDAPEntry, self).clear()
+ self._names.clear()
def __contains__(self, name):
- return super(LDAPEntry, self).__contains__(self._attr_name(name))
+ return self._names.has_key(self._attr_name(name))
def has_key(self, name):
- return super(LDAPEntry, self).has_key(self._attr_name(name))
+ return name in self
# for python-ldap tuple compatibility
def __iter__(self):
--
1.8.1
>From bea28563aa7adcea801ac0538670dbca3ed9c033 Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jchol...@redhat.com>
Date: Thu, 31 Jan 2013 11:56:47 +0100
Subject: [PATCH 3/4] Aggregate IPASimpleLDAPObject in LDAPEntry.
---
ipaserver/ipaldap.py | 15 +++++++++++----
ipaserver/plugins/ldap2.py | 2 +-
tests/test_ipaserver/test_ldap.py | 5 ++++-
3 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/ipaserver/ipaldap.py b/ipaserver/ipaldap.py
index 6268ac0..01fa0c1 100644
--- a/ipaserver/ipaldap.py
+++ b/ipaserver/ipaldap.py
@@ -398,7 +398,7 @@ class IPASimpleLDAPObject(object):
original_dn = dn_tuple[0]
original_attrs = dn_tuple[1]
- ipa_entry = LDAPEntry(DN(original_dn))
+ ipa_entry = LDAPEntry(self, DN(original_dn))
for attr, original_values in original_attrs.items():
target_type = self._SYNTAX_MAPPING.get(self.get_syntax(attr), unicode_from_utf8)
@@ -578,11 +578,16 @@ class IPASimpleLDAPObject(object):
# r[0] == r.dn
# r[1] == r.data
class LDAPEntry(dict):
- __slots__ = ('_dn', '_names', '_orig')
+ __slots__ = ('_conn', '_dn', '_names', '_orig')
- def __init__(self, _dn=None, _obj=None, **kwargs):
+ def __init__(self, _conn, _dn=None, _obj=None, **kwargs):
super(LDAPEntry, self).__init__()
+ if isinstance(_conn, LDAPEntry):
+ assert _dn is None
+ _dn = _conn
+ _conn = _conn._conn()
+
if isinstance(_dn, LDAPEntry):
assert _obj is None
_obj = _dn
@@ -595,8 +600,10 @@ class LDAPEntry(dict):
_obj = {}
orig = None
+ assert isinstance(_conn, IPASimpleLDAPObject)
assert isinstance(_dn, DN)
+ self._conn = lambda: _conn # do not deepcopy me!
self._dn = _dn
self._orig = orig
self._names = CIDict()
@@ -960,7 +967,7 @@ class LDAPClient(object):
return DN((primary_key, entry_attrs[primary_key]), parent_dn)
def make_entry(self, _dn=None, _obj=None, **kwargs):
- return LDAPEntry(_dn, _obj, **kwargs)
+ return LDAPEntry(self.conn, _dn, _obj, **kwargs)
# generating filters for find_entry
# some examples:
diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py
index 6f6c206..2872c80 100644
--- a/ipaserver/plugins/ldap2.py
+++ b/ipaserver/plugins/ldap2.py
@@ -200,7 +200,7 @@ class ldap2(LDAPClient, CrudBackend):
try:
config_entry = getattr(context, 'config_entry')
- return copy.deepcopy(config_entry)
+ return copy.deepcopy(self.conn.make_entry(config_entry))
except AttributeError:
# Not in our context yet
pass
diff --git a/tests/test_ipaserver/test_ldap.py b/tests/test_ipaserver/test_ldap.py
index 06d5d4e..4b0c9d7 100644
--- a/tests/test_ipaserver/test_ldap.py
+++ b/tests/test_ipaserver/test_ldap.py
@@ -156,7 +156,10 @@ class test_ldap(object):
dn1 = DN(('cn', cn1[0]))
dn2 = DN(('cn', cn2[0]))
- e = LDAPEntry(dn1, cn=cn1)
+ self.conn = ldap2(shared_instance=False, ldap_uri=self.ldapuri)
+ self.conn.connect()
+
+ e = LDAPEntry(self.conn.conn, dn1, cn=cn1)
assert e.dn is dn1
assert 'CN' in e
assert e['CN'] is cn1
--
1.8.1
>From 017187c245ab4f16ef375a460be16cad62781d02 Mon Sep 17 00:00:00 2001
From: Jan Cholasta <jchol...@redhat.com>
Date: Thu, 31 Jan 2013 11:57:02 +0100
Subject: [PATCH 4/4] Support attributes with multiple names in LDAPEntry.
---
ipalib/plugins/host.py | 2 --
ipaserver/ipaldap.py | 12 ++++++++++++
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/ipalib/plugins/host.py b/ipalib/plugins/host.py
index e1c07b5..c9bb1ac 100644
--- a/ipalib/plugins/host.py
+++ b/ipalib/plugins/host.py
@@ -406,7 +406,6 @@ class host_add(LDAPCreate):
util.validate_host_dns(self.log, keys[-1])
if 'locality' in entry_attrs:
entry_attrs['l'] = entry_attrs['locality']
- del entry_attrs['locality']
entry_attrs['cn'] = keys[-1]
entry_attrs['serverhostname'] = keys[-1].split('.', 1)[0]
if 'userpassword' not in entry_attrs and not options.get('random', False):
@@ -629,7 +628,6 @@ class host_mod(LDAPUpdate):
raise errors.ACIError(info=_('cn is immutable'))
if 'locality' in entry_attrs:
entry_attrs['l'] = entry_attrs['locality']
- del entry_attrs['locality']
if 'krbprincipalname' in entry_attrs:
(dn, entry_attrs_old) = ldap.get_entry(
dn, ['objectclass', 'krbprincipalname']
diff --git a/ipaserver/ipaldap.py b/ipaserver/ipaldap.py
index 01fa0c1..b8ce270 100644
--- a/ipaserver/ipaldap.py
+++ b/ipaserver/ipaldap.py
@@ -670,6 +670,18 @@ class LDAPEntry(dict):
else:
self._names[name] = name
+ try:
+ schema = self._conn().schema
+ except:
+ pass
+ else:
+ attrtype = schema.get_obj(ldap.schema.AttributeType,
+ name.encode('utf-8'))
+ if attrtype is not None:
+ for altname in attrtype.names:
+ altname = altname.decode('utf-8')
+ self._names[altname] = name
+
super(LDAPEntry, self).__setitem__(name, value)
def setdefault(self, name, default):
--
1.8.1
_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel