summaryrefslogtreecommitdiffstats
path: root/ipaserver/ipaldap.py
diff options
context:
space:
mode:
authorPetr Viktorin <pviktori@redhat.com>2013-01-18 07:48:12 -0500
committerMartin Kosek <mkosek@redhat.com>2013-03-01 16:59:43 +0100
commita7a81238a8caea31c322be9acc19662ca9192870 (patch)
treefe3ba7796e9103f09533d4f48816ce7717e95a70 /ipaserver/ipaldap.py
parent603d9ac418039ebe6e1c83a505b92cd3549077d3 (diff)
downloadfreeipa-a7a81238a8caea31c322be9acc19662ca9192870.tar.gz
freeipa-a7a81238a8caea31c322be9acc19662ca9192870.tar.xz
freeipa-a7a81238a8caea31c322be9acc19662ca9192870.zip
Move entry add, update, remove, rename to LDAPConnection
Also remove _FORCE_REPLACE_ON_UPDATE_ATTRS which was never used. Part of the work for: https://fedorahosted.org/freeipa/ticket/2660
Diffstat (limited to 'ipaserver/ipaldap.py')
-rw-r--r--ipaserver/ipaldap.py135
1 files changed, 135 insertions, 0 deletions
diff --git a/ipaserver/ipaldap.py b/ipaserver/ipaldap.py
index f0f377970..9abd3b722 100644
--- a/ipaserver/ipaldap.py
+++ b/ipaserver/ipaldap.py
@@ -1396,6 +1396,141 @@ class LDAPConnection(object):
self.log.debug("get_members: result=%s", entries)
return entries
+ def add_entry(self, dn, entry_attrs, normalize=True):
+ """Create a new entry."""
+
+ assert isinstance(dn, DN)
+
+ if normalize:
+ dn = self.normalize_dn(dn)
+ # remove all None or [] values, python-ldap hates'em
+ entry_attrs = dict(
+ # FIXME, shouldn't these values be an error?
+ (k, v) for (k, v) in entry_attrs.iteritems()
+ if v is not None and v != []
+ )
+ try:
+ self.conn.add_s(dn, list(entry_attrs.iteritems()))
+ except _ldap.LDAPError, e:
+ self.handle_errors(e)
+
+ def update_entry_rdn(self, dn, new_rdn, del_old=True):
+ """
+ Update entry's relative distinguished name.
+
+ Keyword arguments:
+ del_old -- delete old RDN value (default True)
+ """
+
+ assert isinstance(dn, DN)
+ assert isinstance(new_rdn, RDN)
+
+ dn = self.normalize_dn(dn)
+ if dn[0] == new_rdn:
+ raise errors.EmptyModlist()
+ try:
+ self.conn.rename_s(dn, new_rdn, delold=int(del_old))
+ time.sleep(.3) # Give memberOf plugin a chance to work
+ except _ldap.LDAPError, e:
+ self.handle_errors(e)
+
+ def _generate_modlist(self, dn, entry_attrs, normalize):
+ assert isinstance(dn, DN)
+
+ # get original entry
+ dn, entry_attrs_old = self.get_entry(
+ dn, entry_attrs.keys(), normalize=normalize)
+
+ # generate modlist
+ # for multi value attributes: no MOD_REPLACE to handle simultaneous
+ # updates better
+ # for single value attribute: always MOD_REPLACE
+ modlist = []
+ for (k, v) in entry_attrs.iteritems():
+ if v is None and k in entry_attrs_old:
+ modlist.append((_ldap.MOD_DELETE, k, None))
+ else:
+ if not isinstance(v, (list, tuple)):
+ v = [v]
+ v = set(filter(lambda value: value is not None, v))
+ old_v = set(entry_attrs_old.get(k.lower(), []))
+
+ # FIXME: Convert all values to either unicode, DN or str
+ # before detecting value changes (see IPASimpleLDAPObject for
+ # supported types).
+ # This conversion will set a common ground for the comparison.
+ #
+ # This fix can be removed when ticket 2265 is fixed and our
+ # encoded entry_attrs' types will match get_entry result
+ try:
+ v = set(
+ unicode_from_utf8(self.conn.encode(value))
+ if not isinstance(value, (DN, str, unicode))
+ else value for value in v)
+ except Exception, e:
+ # Rather let the value slip in modlist than let ldap2 crash
+ self.log.error(
+ "Cannot convert attribute '%s' for modlist "
+ "for modlist comparison: %s", k, e)
+
+ adds = list(v.difference(old_v))
+ rems = list(old_v.difference(v))
+
+ is_single_value = self.get_single_value(k)
+
+ value_count = len(old_v) + len(adds) - len(rems)
+ if is_single_value and value_count > 1:
+ raise errors.OnlyOneValueAllowed(attr=k)
+
+ force_replace = False
+ if len(v) > 0 and len(v.intersection(old_v)) == 0:
+ force_replace = True
+
+ if adds:
+ if force_replace:
+ modlist.append((_ldap.MOD_REPLACE, k, adds))
+ else:
+ modlist.append((_ldap.MOD_ADD, k, adds))
+ if rems:
+ if not force_replace:
+ modlist.append((_ldap.MOD_DELETE, k, rems))
+
+ return modlist
+
+ def update_entry(self, dn, entry_attrs, normalize=True):
+ """
+ Update entry's attributes.
+
+ An attribute value set to None deletes all current values.
+ """
+
+ assert isinstance(dn, DN)
+ if normalize:
+ dn = self.normalize_dn(dn)
+
+ # generate modlist
+ modlist = self._generate_modlist(dn, entry_attrs, normalize)
+ if not modlist:
+ raise errors.EmptyModlist()
+
+ # pass arguments to python-ldap
+ try:
+ self.conn.modify_s(dn, modlist)
+ except _ldap.LDAPError, e:
+ self.handle_errors(e)
+
+ def delete_entry(self, dn, normalize=True):
+ """Delete entry."""
+
+ assert isinstance(dn, DN)
+ if normalize:
+ dn = self.normalize_dn(dn)
+
+ try:
+ self.conn.delete_s(dn)
+ except _ldap.LDAPError, e:
+ self.handle_errors(e)
+
class IPAdmin(LDAPConnection):