ReconnectLDAPObject doesn't reconnect after main failure

Alain Spineux aspineux at gmail.com
Sat Jan 27 00:23:00 CET 2007


On 1/26/07, Michael Ströder <michael at stroeder.com> wrote:
> Alain Spineux wrote:
> > When testing ReconnectLDAPObject I found a bug.
> > The object doesn't reconnect after a main failure !
> > [..]
> > I thing the main probleme is here !
> > Look !
>
> Yes, I can reproduce your observation. Thanks for pointing it out.

Don't forget we are on the same boat Captain ! :-)
>
> > l=ldap.ldapobject.ReconnectLDAPObject(ldap_url.initializeUrl())
> > print 'search', l.search_s(ldap_url.dn, ldap.SCOPE_SUBTREE, "(objectClass=*)")
> >
> > this work too ! And don't give any error while their is no bind !
> > work like if l.simple_bind_s('', '') where used just before the search !
>
> Yes, this works as intended in LDAPv3. In opposite to LDAPv2 you MAY
> send a LDAP request without prior bind request.
>
> > I wrote a patch but this is only a workaround that detect the main
> > failure, set a flag and force a reconnect before any request if the
> > flag is set.
>
> Where's the patch?
This is still only a workin "draft" I need to reread it's logic,
anyway I add it at the end
> Can't figure out why it does not send the formerly
> sent bind request. It has all the data around. And if you take the
> server down it will re-send the bind request.

The trick is it doesn't try to reconnect AFTER the main failure (or
BEFORE the next statement) !
Because the first try (of the next ldap statement) doesn't generate
any error, it doesn't try to reconnect and then give the answer as is
! But this is the answer it got like an unauthenticated user !

Look, this is the tcpdump of the last statement !
00:14:21.109514 IP 127.0.0.1.36250 > 127.0.0.1.ldap: S
1795648490:1795648490(0) win 00:14:21.110352 IP 127.0.0.1.ldap >
127.0.0.1.36250: S 1793421325:1793421325(0) ack 1795648491 win 32768
<mss 16396,sackOK,timestamp 516494160 516494159,nop,wscale 7>
00:14:21.110430 IP 127.0.0.1.36250 > 127.0.0.1.ldap: . ack 1 win 257
<nop,nop,timestamp 516494160 516494160>

You can identify the well known 3-way handshaking ! This is a new connection !
I thing libldap open a new connection, but libldap dont store anything
about the credential and then cannot authenticate with the good user !
I will try to reproduce this in C with libc

Here is the patch (including my whoami_s() )

*** ldapobject.py.disconnet     Fri Jan 26 22:22:57 2007
--- ldapobject.py.orig  Fri Jan 26 13:42:59 2007
***************
*** 678,684 ****
      self._retry_delay = retry_delay
      self._start_tls = 0
      self._reconnects_done = 0L
-     self._disconnected=True

    def __getstate__(self):
      """return data representation for pickled object"""
--- 678,683 ----
***************
*** 723,730 ****
            self.start_tls_s()
          # Repeat last simple or SASL bind
          self._apply_last_bind()
!       except Exception, e:
!         self._disconnected=True
          if __debug__ and self._trace_level>=1:
            self._trace_file.write('*** %d. reconnect to %s failed\n' % (
              self._retry_max-reconnect_counter+1,uri
--- 722,728 ----
            self.start_tls_s()
          # Repeat last simple or SASL bind
          self._apply_last_bind()
!       except:
          if __debug__ and self._trace_level>=1:
            self._trace_file.write('*** %d. reconnect to %s failed\n' % (
              self._retry_max-reconnect_counter+1,uri
***************
*** 736,742 ****
            self._trace_file.write('=> delay %s...\n' % (self._retry_delay))
          time.sleep(self._retry_delay)
        else:
-         self._disconnected=False
          if __debug__ and self._trace_level>=1:
            self._trace_file.write('*** %d. reconnect to %s
successful, last operation will be repeated\n' % (
              self._retry_max-reconnect_counter+1,uri
--- 734,739 ----
***************
*** 745,762 ****
          break

    def _apply_method_s(self,func,*args,**kwargs):
!     if self._disconnected:
        self.reconnect(self._uri)
        # Re-try last operation
        return func(self,*args,**kwargs)
-     else:
-         try:
-           return func(self,*args,**kwargs)
-         except ldap.SERVER_DOWN:
-           # Reconnect
-           self.reconnect(self._uri)
-           # Re-try last operation
-           return func(self,*args,**kwargs)

    def set_option(self,option,invalue):
      self._options[option] = invalue
--- 742,754 ----
          break

    def _apply_method_s(self,func,*args,**kwargs):
!     try:
!       return func(self,*args,**kwargs)
!     except ldap.SERVER_DOWN:
!       # Reconnect
        self.reconnect(self._uri)
        # Re-try last operation
        return func(self,*args,**kwargs)

    def set_option(self,option,invalue):
      self._options[option] = invalue
***************
*** 764,772 ****

    def simple_bind_s(self,*args,**kwargs):
      self._last_bind = (self.simple_bind_s,args,kwargs)
!     result=SimpleLDAPObject.simple_bind_s(self,*args,**kwargs)
!     self._disconnected=False
!     return result

    def start_tls_s(self):
      res = SimpleLDAPObject.start_tls_s(self)
--- 756,762 ----

    def simple_bind_s(self,*args,**kwargs):
      self._last_bind = (self.simple_bind_s,args,kwargs)
!     return SimpleLDAPObject.simple_bind_s(self,*args,**kwargs)

    def start_tls_s(self):
      res = SimpleLDAPObject.start_tls_s(self)
***************
*** 778,786 ****
      sasl_interactive_bind_s(who, auth) -> None
      """
      self._last_bind = (self.sasl_interactive_bind_s,args,kwargs)
!     result=SimpleLDAPObject.sasl_interactive_bind_s(self,*args,**kwargs)
!     self._disconnected=False
!     return result

    def add_ext_s(self,*args,**kwargs):
      return self._apply_method_s(SimpleLDAPObject.add_ext_s,*args,**kwargs)
--- 768,774 ----
      sasl_interactive_bind_s(who, auth) -> None
      """
      self._last_bind = (self.sasl_interactive_bind_s,args,kwargs)
!     return SimpleLDAPObject.sasl_interactive_bind_s(self,*args,**kwargs)

    def add_ext_s(self,*args,**kwargs):
      return self._apply_method_s(SimpleLDAPObject.add_ext_s,*args,**kwargs)
***************
*** 800,808 ****
    def search_ext_s(self,*args,**kwargs):
      return self._apply_method_s(SimpleLDAPObject.search_ext_s,*args,**kwargs)

-   def whoami_s(self,*args,**kwargs):
-     return self._apply_method_s(SimpleLDAPObject.whoami_s,*args,**kwargs)
-

  class SmartLDAPObject(ReconnectLDAPObject):
    """
--- 788,793 ----



--
Alain Spineux
aspineux gmail com
May the sources be with you



More information about the python-ldap mailing list