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 | |
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')
-rw-r--r-- | ipaserver/ipaldap.py | 135 | ||||
-rw-r--r-- | ipaserver/plugins/ldap2.py | 144 |
2 files changed, 137 insertions, 142 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): diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py index d7cd0a4e..2852c4d4 100644 --- a/ipaserver/plugins/ldap2.py +++ b/ipaserver/plugins/ldap2.py @@ -29,16 +29,14 @@ Backend plugin for LDAP. import copy import os -import time import re import pwd import krbV import ldap as _ldap -from ipapython.dn import DN, RDN -from ipaserver.ipaldap import ( - SASL_AUTH, unicode_from_utf8, IPASimpleLDAPObject, LDAPConnection) +from ipapython.dn import DN +from ipaserver.ipaldap import SASL_AUTH, IPASimpleLDAPObject, LDAPConnection try: @@ -64,9 +62,6 @@ class ldap2(LDAPConnection, CrudBackend): """ LDAP Backend Take 2. """ - # attributes in this list cannot be deleted by update_entry - # only MOD_REPLACE operations are generated for them - _FORCE_REPLACE_ON_UPDATE_ATTRS = [] def __init__(self, shared_instance=True, ldap_uri=None, base_dn=None, schema=None): @@ -204,24 +199,6 @@ class ldap2(LDAPConnection, CrudBackend): return dn - 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) - config_defaults = {'ipasearchtimelimit': [2], 'ipasearchrecordslimit': [0]} def get_ipa_config(self, attrs_list=None): """Returns the IPA configuration entry (dn, entry_attrs).""" @@ -360,123 +337,6 @@ class ldap2(LDAPConnection, CrudBackend): return False - 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 k in self._FORCE_REPLACE_ON_UPDATE_ATTRS or is_single_value: - force_replace = True - elif 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) - def modify_password(self, dn, new_pass, old_pass=''): """Set user password.""" |