Closed senfomat closed 3 years ago
Hi, the default value for connect_async
is True on Linux, you have to call bonsai.set_connect_async(False)
explicitly to turn it off.
Is the IPC protocol (ldapi) affected only or the basic ones (ldap/ldaps) as well?
Hi, the default value for
connect_async
is True on Linux, you have to callbonsai.set_connect_async(False)
explicitly to turn it off.
Turning it off, even the succeeding call leak filedescriptors.
Is the IPC protocol (ldapi) affected only or the basic ones (ldap/ldaps) as well?
I just tested with ldap:// . It left the TCP-Connection open, until the script was exiting. And it leaked the succeeding calls as well, with our without the async-setting from above.
Thank you for the extra information, I'll look into it.
When I change the try:-block like this:
session = False
try:
- client.connect()
+ with client.connect():
+ pass
except AuthenticationError as err:
print(f"LDAP-Authentication for '{username}' failed: {err}")
the succeeding calls always get closed, even with ldap:// and with ldapi:// and async=True
or async=False
.
But no change for the auth-failed-Calls at all, these connections stay open.
Have you tried using a finally block?
def LDAPAuthenticate(username, password):
client = LDAPClient("ldapi://%2Frun%2Fslapd%2Fldapi")
client.set_credentials("SIMPLE", user=f"uid={username},cn=people,dc=domain.org", password=password)
session = False
try:
conn = client.connect()
except AuthenticationError as err:
log_error(f"LDAP-Authentication for '{username}' failed: {err}")
except Exception as e:
log_error(f"LDAP-Service failed: {e}")
else:
log_debug(f"LDAP-Authentication for '{username}' succeeded.")
session = True
finally:
conn.close()
return session
Edit: On second thought: on error the variable bind will fail, and then conn
will be an unbound variable in the finally block I suppose. But it seems your input narrows it down pretty well. On connection error the close function should be called on C's side during the clean up.
Using your suggestion the failing connections get this stracktrace:
Traceback (most recent call last):
File "./test.py", line 71, in <module>
loginf()
File "./test.py", line 41, in loginf
print(LDAPAuthenticate(username, password))
File "./test.py", line 33, in LDAPAuthenticate
conn.close()
UnboundLocalError: local variable 'conn' referenced before assignment
the succeeding connections get closed as stated. but the failed connections gives a False
as return-value, where close() is not available.
Added to call ldap_unbind_ext
during LDAPConnection
object's deallocation. That will handle freeing the file descriptors, allocated by the LDAP structure. Same LDAP API function is called during the LDAPConnection.close()
method.
The fix in the refactor-ci-branch works for us, no fd-leakage or open ports anymore. Thank you! (The ticket can get closed, but I dont know if you want to let it stay open until the merge into master)
Thank you for reporting it in such details.
The Setup
We are using bonsai to authenticate OpenVPN-users via a Python-Flask-Webservice.
We are using:
bonsai, v1.2.0
installed via piplibldap-2.4-2, v2.4.49+dfsg-2ubuntu1.5
libldap2-dev, v2.4.49+dfsg-2ubuntu1.5
For the authentication we have the following function:
The Problem
When a users enters a wrong password within this authentication, every call to LDAPAuthenticate() leaks around 14 filedescriptors on the ldapi-Socketconnection, which gets not closed after the connect()-call. These connections are only closed, when the python3-webservice process exits or the slapd gets restarted.
When this wrong authentication is done a few hundred times (as some of our users have misconfigured clients), the ldap-daemon stops responding at all, as the number of maximum open filedescriptors is exhausted.
We have installed a workaround to restart the gunicorn-Webservice-Processes after 100 Requests. That we can not reach the fd-limit on the slapd.
Debuglogs
The connection-debug of a failed connection (using
bonsai.set_debug(True)
):The connection with a working auth looks like this:
We are not sure, why the bonsai-Module is doing the connection in async mode. We do not want this, we left it on the default of
False
. But as the debuglog shows in the middle, the module is forcing it to async.