diff --git a/pykolab/auth/ldap/__init__.py b/pykolab/auth/ldap/__init__.py --- a/pykolab/auth/ldap/__init__.py +++ b/pykolab/auth/ldap/__init__.py @@ -116,7 +116,8 @@ pykolab.base.Base.__init__(self, domain=domain) self.ldap = None - self.bind = False + self.bind = None + if domain == None: self.domain = conf.get('kolab', 'primary_domain') else: @@ -225,13 +226,9 @@ (entry_dn, entry_attrs) = _result_data[0] try: - log.debug(_("Binding with user_dn %s and password %s") - % (entry_dn, '*' * len(login[1]))) - # Needs to be synchronous or succeeds and continues setting retval # to True!! - self.ldap.simple_bind_s(entry_dn, login[1]) - retval = True + retval = self._bind(entry_dn, login[1]) try: auth_cache.set_entry(_filter, entry_dn) except Exception, errmsg: @@ -255,18 +252,14 @@ retval = False else: try: - log.debug(_("Binding with user_dn %s and password %s") - % (entry_dn, '*' * len(login[1]))) - # Needs to be synchronous or succeeds and continues setting retval # to True!! - self.ldap.simple_bind_s(entry_dn, login[1]) + retval = self._bind(entry_dn, login[1]) auth_cache.set_entry(_filter, entry_dn) - retval = True except ldap.NO_SUCH_OBJECT, errmsg: log.debug(_("Error occured, there is no such object: %r") % (errmsg), level=8) - self.bind = False + self.bind = None try: auth_cache.del_entry(_filter) except: @@ -981,8 +974,11 @@ return entry_modifications def reconnect(self): + bind = self.bind self._disconnect() self.connect() + if bind is not None: + self._bind(bind['dn'], bind['pw']) def search_entry_by_attribute(self, attr, value, **kw): self._bind() @@ -1006,13 +1002,15 @@ override_search='_regular_search' ) - def set_entry_attribute(self, entry_id, attribute, value): log.debug(_("Setting entry attribute %r to %r for %r") % (attribute, value, entry_id), level=9) self.set_entry_attributes(entry_id, { attribute: value }) def set_entry_attributes(self, entry_id, attributes): - self._bind() + bind_dn = self.config_get('bind_dn') + bind_pw = self.config_get('bind_pw') + + self._bind(bind_dn, bind_pw) entry_dn = self.entry_dn(entry_id) @@ -1046,6 +1044,9 @@ except: log.error(_("Could not update dn %r:\n%r") % (dn, modlist)) + # Drop the privileges + self._unbind() + def synchronize(self, mode=0, callback=None): """ Synchronize with LDAP @@ -1183,26 +1184,45 @@ ### API depth level increasing! ### - def _bind(self): - if self.ldap == None: + def _bind(self, bind_dn=None, bind_pw=None): + # If we have no LDAP, we have no previous state. + if self.ldap is None: + self.bind = None self.connect() - if not self.bind: - bind_dn = self.config_get('bind_dn') - bind_pw = self.config_get('bind_pw') + # If we are to bind as foo, we have no state. + if bind_dn is not None: + self.bind = None + + # Only if we have no state and no bind credentials specified in the + # function call. + if self.bind is None: + + if bind_dn is None: + bind_dn = self.config_get('service_bind_dn') + + if bind_pw is None: + bind_pw = self.config_get('service_bind_pw') + + if bind_dn is not None: + log.debug(_("Binding with bind_dn: %s and password: %s") + % (bind_dn, '*' * len(bind_pw))) # TODO: Binding errors control try: self.ldap.simple_bind_s(bind_dn, bind_pw) - self.bind = True + self.bind = {'dn': bind_dn, 'pw': bind_pw} + return True except ldap.SERVER_DOWN, errmsg: log.error(_("LDAP server unavailable: %r") % (errmsg)) log.error(_("%s") % (traceback.format_exc())) + return False except ldap.INVALID_CREDENTIALS: log.error(_("Invalid DN, username and/or password.")) - + return False else: - log.debug(_("_bind called, but already bound"), level=9) + log.debug(_("bind() called but already bound"), level=8) + return True def _change_add_group(self, entry, change): """ @@ -1979,7 +1999,7 @@ self._unbind() del self.ldap self.ldap = None - self.bind = False + self.bind = None def _domain_naming_context(self, domain): self._bind() @@ -2172,11 +2192,7 @@ log.debug(_("Finding domain root dn for domain %s") % (domain), level=8) - bind_dn = conf.get('ldap', 'bind_dn') - bind_pw = conf.get('ldap', 'bind_pw') - domain_base_dn = conf.get('ldap', 'domain_base_dn', quiet=True) - domain_filter = conf.get('ldap', 'domain_filter') if not domain_filter == None: @@ -2257,9 +2273,7 @@ log.debug(_("Listing domains..."), level=8) self.connect() - - bind_dn = conf.get('ldap', 'bind_dn') - bind_pw = conf.get('ldap', 'bind_pw') + self._bind() domain_base_dn = conf.get('ldap', 'domain_base_dn', quiet=True) @@ -2277,12 +2291,6 @@ if domain_base_dn == None or domain_filter == None: return [] - # TODO: this function should be wrapped for error handling - try: - self.ldap.simple_bind_s(bind_dn, bind_pw) - except ldap.SERVER_DOWN, e: - raise AuthBackendError, _("Authentication database DOWN") - dna = self.config_get('domain_name_attribute') if dna == None: dna = 'associateddomain' @@ -2319,13 +2327,6 @@ return domains - def _reconnect(self): - """ - Reconnect to LDAP - """ - self._disconnect() - self.connect() - def _synchronize_callback(self, *args, **kw): """ Determine the characteristics of the callback being placed, and @@ -2446,7 +2447,7 @@ """ self.ldap.unbind() - self.bind = False + self.bind = None ### ### Backend search functions