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: wrap socket error: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:1123) #925

Closed
sebastian-luna-valero opened this issue Feb 26, 2021 · 13 comments
Labels
external issue A problem that comes from another library or resource, which ldap3 interacts with or is used by question

Comments

@sebastian-luna-valero
Copy link

Hi,

I am indirectly using ldap3 to offer LDAP authentication on a JupyterHub deployment with kubernetes. I am always using the same LDAP server, and I have tested it with the following JupyterHub versions:

  • JupyterHub 0.9.1 ships ldap3 version 2.7
  • JupyterHub 0.10.6 ships ldap3 version 2.8.1
  • JupyterHub 0.11.1 ships ldap3 version 2.8.1

I found that JupyterHub 0.9.1 with ldap3 version 2.7 works correctly with our LDAP server. However, JupyterHub deployments with ldap3 version 2.8.1 do not work and they throw the following exception:

ldap3.core.exceptions.LDAPStartTLSError: ('wrap socket error: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:1123)',)

This issue has been previously reported in:

I am not sure how to help solve this problem, any ideas?

Best regards,
Sebastian

@zorn96 zorn96 added external issue A problem that comes from another library or resource, which ldap3 interacts with or is used by question labels Feb 27, 2021
@zorn96
Copy link
Collaborator

zorn96 commented Feb 27, 2021

hi @sebastian-luna-valero ! the SSL negotiation for ldap3 isn't native to the ldap3 library. it just uses the python ssl libraries, and that's where this error bubbles up from.
so it seems like it an issue with the underlying system.

I suspect that the older version of JupyterHub might not have disabled SSLv3. or it might be on an older system with older openssl or older python.
could you run

>>> import ssl
>>> print(ssl.OPENSSL_VERSION)

on every system and show the output? that will key us in to any discrepancies in underlying SSL versions

beyond that, it's also possible that Jupyter's settings in terms of allowable SSL connections changed across versions, or that the machines themselves have configurations restricting ciphers and causing a negotiation failure.
if that's potentially the case, the we'd want to take a packet capture on each machine. don't worry, it won't capture any sensitive data. we'd just want to see the TLS handshake and see what supported ciphers and versions are being sent by each client, as a mismatch between client and server could lead us to this issue.

packet captures are a lot of work though, so let's start by just trying to capture the ssl info on each machine using the python shell commands above

if you're skeptical - I have multiple pythons on my laptop because I use pyenv, and here's my output from different pythons

Azarias-MacBook-Pro:~ azariazornberg$ python
Python 2.7.10 (v2.7.10:15c95b7d81dc, May 23 2015, 09:33:12) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import ssl
>>> ssl.OPENSSL_VERSION
'OpenSSL 0.9.8zh 14 Jan 2016'
>>> quit()
Azarias-MacBook-Pro:~ azariazornberg$ python3
Python 3.8.2 (default, Dec 21 2020, 15:06:04) 
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import ssl
>>> ssl.OPENSSL_VERSION
'LibreSSL 2.8.3'
>>> quit()
Azarias-MacBook-Pro:~ azariazornberg$ pyenv shell 3.7.9
Azarias-MacBook-Pro:~ azariazornberg$ pyenv shell
3.7.9
Azarias-MacBook-Pro:~ azariazornberg$ python
Python 3.7.9 (default, Feb 26 2021, 17:37:29) 
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import ssl
>>> ssl.OPENSSL_VERSION
'OpenSSL 1.1.1i  8 Dec 2020'
>>> quit()
Azarias-MacBook-Pro:~ azariazornberg$ pyenv shell 3.8.7
Azarias-MacBook-Pro:~ azariazornberg$ python
Python 3.8.7 (default, Feb 26 2021, 17:39:13) 
[Clang 12.0.0 (clang-1200.0.32.29)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import ssl
>>> ssl.OPENSSL_VERSION
'OpenSSL 1.1.1i  8 Dec 2020'
>>> 

so the system python2 uses openssl, but the system python3 uses Apple's default LibreSSL. the python 3.7 and 3.8 i installed with pyenv use openssl, but the newer 1.1.1i. so there's SSL packages all over the place and it makes a big difference in the handshake

@sebastian-luna-valero
Copy link
Author

Thanks @zorn96

JupyterHub 0.9.1 ships with:

  • OpenSSL 1.1.1 11 Sep 2018
  • Python 3.6.9
  • PyOpenSSL version 19.1.0

Output:

$ python3
Python 3.6.9 (default, Nov  7 2019, 10:44:02) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import ssl
>>> ssl.OPENSSL_VERSION
'OpenSSL 1.1.1  11 Sep 2018'

JupyterHub 0.11.1 ships with:

  • OpenSSL 1.1.1f 31 Mar 2020
  • Python 3.8.5
  • PyOpenSSL version 20.0.0

Output:

jovyan@hub-788c8656cb-xqx7s:/srv/jupyterhub$ python3 
Python 3.8.5 (default, Jul 28 2020, 12:59:40) 
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import ssl
>>> ssl.OPENSSL_VERSION
'OpenSSL 1.1.1f  31 Mar 2020'

For future reference, here are the commands I used:

# log into hub pod
kubectl exec -it pod/hub-789fd4dc88-lzx4h /bin/bash

# check PyOpenSSL version
cat /usr/local/lib/python3.6/dist-packages/OpenSSL/version.py

# check OpenSSL version
openssl
version

Could you infer what the root cause of the problem is according to the above output?

Many thanks,
Sebastian

@zorn96
Copy link
Collaborator

zorn96 commented Mar 3, 2021

ah yeah, I think I have an idea.
python3.7 introduced a number of breaking changes to built-in libraries. from some google searching, I'm seeing a number of people who started encountering ssl issues with older version (TLS1.0, SSLv3) when going from python 3.6 to 3.7/3.8; I suspect you're seeing something similar

so it's not a problem with the ldap3 library. something in the jupyter confg is causing SSLv3 to get negotiated (bad cipher suites? old keys/certs? old libraries on the instance hosting it? I can't tell without looking at it, and I'm not a jupyter expert anyway), and the client with newer python is having trouble because SSLv3 cannot be negotiated by default

there's sort of 2 paths here:

  1. the ideal end solution here (in my opinion) is to get everything using TLS1.2 or TLS1.3; if we're trying to negotiate SSLv3 then it seems like something whether it be version config or cipher config is forcing a downgrade. the most secure solution is to get everything to the newer TLS. so you'd look at your jupyter config and local system config around supported versions and ciphers and change that to fix it
  2. you can try to change the configuration of ssl on the client to allow SSLv3 in order to avoid any potential need to change the jupyter hub. this is very insecure though, and at that point I'd ask why you're even using ldaps at all, because SSLv3 is very broken. this is probably easier to do, but again, you may as well use plaintext ldap if you're going to do this because SSLv3 won't stop determined attackers

@sebastian-luna-valero
Copy link
Author

Many thanks @zorn96

Let me report back to jupyterhub/ldapauthenticator#194 and see whether they can help.

Best regards,
Sebastian

@sebastian-luna-valero
Copy link
Author

Hi,

I just wanted to add that all these JupyterHub deployments have been performed with the same OpenStack Magnum tool so the underlying virtual infrastructure is always the same.

Best regards,
Sebastian

@sebastian-luna-valero
Copy link
Author

Hi again,

Sorry, I think it will be most helpful if I paste here the full traceback below:

    HTTPServerRequest(protocol='http', host='test', method='POST', uri='/hub/login?next=%2Fiaa%2Fhub%2F', version='HTTP/1.1', remote_ip='::ffff:192.168.100.79')                             
    Traceback (most recent call last):
      File "/usr/local/lib/python3.8/dist-packages/tornado/web.py", line 1704, in _execute
        result = await result
      File "/usr/local/lib/python3.8/dist-packages/jupyterhub/handlers/login.py", line 144, in post
        user = await self.login_user(data)
      File "/usr/local/lib/python3.8/dist-packages/jupyterhub/handlers/base.py", line 749, in login_user
        authenticated = await self.authenticate(data)
      File "/usr/local/lib/python3.8/dist-packages/jupyterhub/auth.py", line 462, in get_authenticated_user                                                                                                       
        authenticated = await maybe_future(self.authenticate(handler, data))
      File "/usr/local/lib/python3.8/dist-packages/ldapauthenticator/ldapauthenticator.py", line 382, in authenticate                                                                                             
        try:
      File "/usr/local/lib/python3.8/dist-packages/ldapauthenticator/ldapauthenticator.py", line 314, in get_connection                                                                                           
        )
      File "/usr/local/lib/python3.8/dist-packages/ldap3/core/connection.py", line 356, in __init__
        self._do_auto_bind()
      File "/usr/local/lib/python3.8/dist-packages/ldap3/core/connection.py", line 384, in _do_auto_bind
        if self.start_tls(read_server_info=False):
      File "/usr/local/lib/python3.8/dist-packages/ldap3/core/connection.py", line 1307, in start_tls
        if self.server.tls.start_tls(self) and self.strategy.sync:  # for asynchronous connections _start_tls is run by the strategy                                                                              
      File "/usr/local/lib/python3.8/dist-packages/ldap3/core/tls.py", line 280, in start_tls
        return self._start_tls(connection)
      File "/usr/local/lib/python3.8/dist-packages/ldap3/core/tls.py", line 289, in _start_tls
        raise start_tls_exception_factory(e)(connection.last_error)
    ldap3.core.exceptions.LDAPStartTLSError: ('wrap socket error: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:1123)',)                 

Does this help?

Best regards,
Sebastian

@zorn96
Copy link
Collaborator

zorn96 commented Mar 5, 2021

hi @sebastian-luna-valero - this is definitely not an ldap3 library issue. this error is bubbling up from the ssl library. so I'm not sure that I can render much further assistance. the stacktrace doesn't tell us anything new

@sebastian-luna-valero
Copy link
Author

Thank you very much for your help @zorn96

Before closing the issue, I will try to find a solution and report back.

@dangelsaurus
Copy link

dangelsaurus commented Nov 1, 2021

wanted to add a bit here... Looks like in my case, this is a python 3.10 issue as well. no issues on 3.8 or 3.9, but as soon as I try with 3.10 I get the same error..

from ldap3 import Server, Connection, ALL, SUBTREE, Tls
import ssl
tls_config = Tls(validate=ssl.CERT_NONE)

server = Server('xxx.xxx.xxx', use_ssl=True, get_info=ALL, tls=tls_config)

conn = Connection(server, 'cn=<username>,cn=applications,dc=xxx,dc=xxx', '<password>', )
conn.bind()


Traceback (most recent call last):
  File "C:\Users\xxxx\xxxxxx\Python\pins\default.py", line 14, in <module>
    conn.bind()
  File "C:\Users\xxxx\.virtualenvs\pins-piSePCmt\lib\site-packages\ldap3\core\connection.py", line 589, in bind
    self.open(read_server_info=False)
  File "C:\Users\xxxx\.virtualenvs\pins-piSePCmt\lib\site-packages\ldap3\strategy\sync.py", line 57, in open
    BaseStrategy.open(self, reset_usage, read_server_info)
  File "C:\Users\xxxx\.virtualenvs\pins-piSePCmt\lib\site-packages\ldap3\strategy\base.py", line 146, in open
    raise exception_history[0][0]
ldap3.core.exceptions.LDAPSocketOpenError: ("('socket ssl wrapping error: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:997)',)",)

Related?

The deprecated protocols SSL 3.0, TLS 1.0, and TLS 1.1 are no longer officially supported. Python does not block them actively. However OpenSSL build options, distro configurations, vendor patches, and cipher suites may prevent a successful handshake.

@zorn96
Copy link
Collaborator

zorn96 commented Nov 1, 2021

Hi @dangelsaurus i spoke to this on a more recent issue as well - python 3.10 changes the minimum openssl version default for python, and the newer openssl deprecated a lot of stuff.

So this issue you’re seeing is unrelated to the library, and is more of a general python/openssl issue. You could change your python install to use a different system library for ssl, or build your openssl with options to loosen its restrictions to fix this. But that’s all external to python itself really

@zorn96 zorn96 closed this as completed Nov 1, 2021
@tschloesser
Copy link

HI,
I am running into the same issue after upgrading to python 3.10 on my Mac today. Unfortunately, I am quite new to Python, so I am getting a kind of lost here.

Can anybody provide a hint on how to change the Python 3.10 code to work with OpenSSL 1.1.1l provided by the Python install?

BTW: I Only want to establish a secure LDAP connection with a server providing a self-signed certificate - This was working with Python 3.8.9 and LibreSSL 2.8.3

Kind regrads

Throsten

@zorn96
Copy link
Collaborator

zorn96 commented Jan 28, 2022

hi @tschloesser ! if you want to use older SSL, I believe the way to do it is to create an SSLContext object (ldap3 supports using these) and specify the protocol version to allow for TLS1.0

so you'd do something like

import ssl
context = ssl.SSLContext(protocol=ssl.PROTOCOL_TLS)

(plus any other options you may need around trusted ca paths) and then use that. for info on SSLContext in general, you'll want to look at the python ssl docs.

@tschloesser
Copy link

tschloesser commented Jan 28, 2022 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
external issue A problem that comes from another library or resource, which ldap3 interacts with or is used by question
Projects
None yet
Development

No branches or pull requests

4 participants