diff options
author | Petr Viktorin <pviktori@redhat.com> | 2013-01-18 07:48:12 -0500 |
---|---|---|
committer | Martin Kosek <mkosek@redhat.com> | 2013-03-01 16:59:43 +0100 |
commit | a7a81238a8caea31c322be9acc19662ca9192870 (patch) | |
tree | fe3ba7796e9103f09533d4f48816ce7717e95a70 /ipaserver/ipaldap.py | |
parent | 603d9ac418039ebe6e1c83a505b92cd3549077d3 (diff) | |
download | freeipa.git-a7a81238a8caea31c322be9acc19662ca9192870.tar.gz freeipa.git-a7a81238a8caea31c322be9acc19662ca9192870.tar.xz freeipa.git-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.py | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/ipaserver/ipaldap.py b/ipaserver/ipaldap.py index f0f37797..9abd3b72 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): |