Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ldap3.core.exceptions.LDAPStartTLSError: automatic start_tls befored bind not successful #855

Closed
1kastner opened this issue Aug 12, 2020 · 7 comments
Labels

Comments

@1kastner
Copy link
Contributor

1kastner commented Aug 12, 2020

I recently encountered a problem with ldap3 that seems to be related to the last update of ldap3 from 2.7 to 2.8. I only use the library in an indirect fashion so I first reported the problem there, see jupyterhub/ldapauthenticator#171 for a detailed discussion. However, I summarize the main points in the following.

In these lines of the module a connection is set up. Either ldap3.AUTO_BIND_TLS_BEFORE_BIND or ldap3.AUTO_BIND_NO_TLS is used. They are mapped on the strings 'TLS_BEFORE_BIND' and 'NO_TLS'.

A git blame on that file also shows that the code has been there for over a year. With ldap3 version 2.7 that has always worked nicely. If I replace it with ldap3 version 2.8, the following error shows up in the logs:

[...]
      File "/opt/conda/lib/python3.6/site-packages/ldapauthenticator/ldapauthenticator.py", line 382, in authenticate
        conn = self.get_connection(userdn, password)
      File "/opt/conda/lib/python3.6/site-packages/ldapauthenticator/ldapauthenticator.py", line 315, in get_connection
        server, user=userdn, password=password, auto_bind=auto_bind
      File "/opt/conda/lib/python3.6/site-packages/ldap3/core/connection.py", line 356, in __init__
        self._do_auto_bind()
      File "/opt/conda/lib/python3.6/site-packages/ldap3/core/connection.py", line 391, in _do_auto_bind
        raise LDAPStartTLSError(error)
    ldap3.core.exceptions.LDAPStartTLSError: automatic start_tls befored bind not successful

Furthermore, one user stated that by just re-installing version 2.7 everything works smoothly again in our ticket discussion. Do you have an idea where the error stems from? What can we do to resolve this?

EDIT: We have frozen https://github.com/jupyterhub/ldapauthenticator to the version 2.7 because the changes introduced in version 2.8 of ldap3 created problems for several users of that library.

@1kastner
Copy link
Contributor Author

The code in isolation here (with example parameter values):

server_address = "ldaps:/XXX"
server_port = 636
use_ssl = True
user_dn = "uid={username},ou=people,dc=wikimedia,dc=org"

server = ldap3.Server(
    server_address, port=server_port, use_ssl=use_ssl
)
auto_bind = (
    use_ssl and ldap3.AUTO_BIND_TLS_BEFORE_BIND or ldap3.AUTO_BIND_NO_TLS
)
conn = ldap3.Connection(
    server, user=userdn, password=password, auto_bind=auto_bind
)

Is the library used in a wrong way here?

@1kastner
Copy link
Contributor Author

1kastner commented Aug 16, 2020

I compared the code with the tag v2.7 with the newer version v2.8 and in fact the auto_bind behavior did undergo some larger changes, see the diff (and following lines) and the git blame.

A question since this change broke things that previously worked: Are there any tests covering this specific auto_bind behavior?

@cannatag
Copy link
Owner

Hi, in 2.8 there are some additional check on start_tls(). Start_tls() is an LDAP operation that secures an unsecure socket with TLS. In your code the socket is already secure because you established the secure connection with 'ldaps://...' or the use_ssl parameter, so you can simply set auto_bind to True because the socket is already in TLS.

In version previous to 2.8 this behaviour was silently failing and now an error is raised.

So you code should be:
auto_bind = ( use_ssl and ldap3.AUTO_BIND_NO_TLS or ldap3.AUTO_BIND_TLS_BEFORE_BIND )

That is, if your connection is set as secure (use_ssl=True) opens the socket with SSL/TLS and perform the bind() operation, while if your connection is unsecure (use_ssl=False) opens the socket without SSL/TLS, performs the start_tls() operation and if the operation is successful performs the bind() operation (on the secured socket).

I suggest you to set use_ssl to True, so the socket is secure from the very start of the connection. You should use the start_tls() operation only if you cannot reach the server on its secure port, usually 636, but only on the cleartext (unsecure) port, usually 389.

Let me know if you still have problems.

Thanks for using the ldap3 library,
Giovanni

@1kastner
Copy link
Contributor Author

Thank you very much for the detailled feedback! If it is ok for you, I will close the issue and in case we encounter problems during the implementation, I will turn back to this thread.

1kastner added a commit to 1kastner/ldapauthenticator that referenced this issue Aug 17, 2020
1kastner added a commit to 1kastner/ldapauthenticator that referenced this issue Aug 17, 2020
@1kastner
Copy link
Contributor Author

Actually you had a twist in the suggested code, see

>>> import ldap3
>>> use_ssl = True
>>> use_ssl and ldap3.AUTO_BIND_NO_TLS or ldap3.AUTO_BIND_TLS_BEFORE_BIND
'NO_TLS'
>>> use_ssl = False
>>> use_ssl and ldap3.AUTO_BIND_NO_TLS or ldap3.AUTO_BIND_TLS_BEFORE_BIND
'TLS_BEFORE_BIND'

I guess you meant it just the other way around, switching the two constants.

The way the logical operators AND and OR operate is always confusing so I rewrote the above code to

ldap3.AUTO_BIND_TLS_BEFORE_BIND if self.use_ssl else ldap3.AUTO_BIND_NO_TLS

The code you suggested is equal to a) the line above (except the twist) and b) to what I have provided in the beginning of this issue, isn't it? You also suggest to work with the same constants that are supposed to work.

The code you suggested (after switching the two constants) still runs into troubles, see the docker-compose logs:

jupyterhub_1_32e38f00fe9e |       File "/opt/conda/lib/python3.6/site-packages/ldapauthenticator/ldapauthenticator.py", line 382, in authenticate
jupyterhub_1_32e38f00fe9e |         conn = self.get_connection(userdn, password)
jupyterhub_1_32e38f00fe9e |       File "/opt/conda/lib/python3.6/site-packages/ldapauthenticator/ldapauthenticator.py", line 315, in get_connection
jupyterhub_1_32e38f00fe9e |         server, user=userdn, password=password, auto_bind=auto_bind
jupyterhub_1_32e38f00fe9e |       File "/opt/conda/lib/python3.6/site-packages/ldap3/core/connection.py", line 356, in __init__
jupyterhub_1_32e38f00fe9e |         self._do_auto_bind()
jupyterhub_1_32e38f00fe9e |       File "/opt/conda/lib/python3.6/site-packages/ldap3/core/connection.py", line 391, in _do_auto_bind
jupyterhub_1_32e38f00fe9e |         raise LDAPStartTLSError(error)
jupyterhub_1_32e38f00fe9e |     ldap3.core.exceptions.LDAPStartTLSError: automatic start_tls befored bind not successful
jupyterhub_1_32e38f00fe9e |

Is there maybe a logical flaw somewhere else?

@1kastner 1kastner reopened this Aug 17, 2020
@cannatag
Copy link
Owner

HI, my code is correct. If you use the use_ssl=True parameter the connection is already secure, so during bind you don't need the start_tls operation. for that reason you can use the AUTO_BIND_NO_TLS. If your connection is not secured you can use the AUTO_BIND_TLS_BEFORE_BIND. The TLS in the auto_bind parameter refers to the StartTLS LDAP operation that you can perform only if you're on a cleartext connection.

@1kastner
Copy link
Contributor Author

Thank you very much for your patience, I definitely need to learn more about ldap

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants