-
Notifications
You must be signed in to change notification settings - Fork 13
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
Allow urllib3 v2.0 #105
Allow urllib3 v2.0 #105
Conversation
While most failures are unrelated and due to the test suite reaching out to httpbin.org, I would like to understand what this new warning is:
|
I'm looking at that right now, too. The full warning message is:
When I check the fingerprint it doesn't match the fingerprint on the test: openssl s_client -connect httpbin.org:443 -showcerts </dev/null | openssl x509 -noout -sha256 -fingerprint
# FF:77:C6:EA:49:81:71:84:63:B3:45:12:2F:9B:A0:00:34:B4:78:00:12:E8:91:47:FB:EB:56:1F:9A:63:BB:CC I changed the tests to use that fingerprint and ran them locally, but the same warnings persisted. I don't know this library well enough at all (yet) to understand the issue here. Since the test is specifically for testing SSL I'm not comfortable squashing an @sethmlarson is, coincidentally, the maintainer of |
I was able to resolve the warnings for
I'm not a daily user of this package, and so I won't know the different use cases for it, but I'm not sure if we should enforce CERT_REQUIRED. |
As it turns out I'm also an urllib3 maintainer, but this took quite some digging. In urllib3 1.26.x, we considered a connection verified if assert_fingerprint was not None, but in urllib3 2.0 we changed it to check if it was truthy using
elastic-transport-python hacks into the internals of urllib3 which is unsupported. I can see three options here:
@sethmlarson @JoshMock What do you think? |
@JoshMock I think we should investigate in the third option suggested by @pquentin:
I'm also looking into this but definitely something to fix for security reason. We should not bypass this check. |
@pquentin I'm very confused about this block and the nested comment. Does this call happen before the validation from urllib2 or after it? |
@aqeelat It happens before. If you look at more context:
You can see that elastic-transport-python is inheriting from The reason urllib3's validation is disabled is that elastic-transport-python does its own validation: elastic-transport-python/elastic_transport/_node/_urllib3_chain_certs.py Lines 113 to 122 in d25528c
The equivalent in urllib3 is assert_fingerprint: https://github.com/urllib3/urllib3/blob/2ac40569acb464074bdc3f308124d781d6aa0860/src/urllib3/util/ssl_.py#L146-L173 @ezimuel @JoshMock The additions in elastic-transport-python allow pinning any certificate in the chain, not just the leaf certificate as in urllib3. Seth has blogged about this extensively at https://sethmlarson.dev/experimental-python-3.10-apis-and-trust-stores. Even if we move that code to urllib3, it will only be for 2.0.x, not 1.26.x which is still widely used, so I would actually suggest option 2 here: setting |
Thanks for all the context @pquentin. 🙏
@ezimuel Whatever option means we depend on validated, well-tested upstream security practices (in urllib3 in this case) rather than writing and maintaining our own custom security validation schemes would be my preference. Unless there's some Elasticsearch-specific reasoning for it, and I really hope there isn't. 😄 |
I also hoped that root CA pinning support was simply to add system certificate stores support! This is quite common in enterprise companies: to avoid paying for hundreds or thousands of public certificates, they have their own root certificates installed on every computer, and most software can use it transparently. But not Python as it uses OpenSSL which does not support this. If this was the reason for However, I discussed quickly with Seth today and Sorry to disappoint! |
So httpbin.org keeps timing out for me which makes testing harder, but this diff is compatible with urllib3 1.26 and 2.0. It fixes the warning by using the public diff --git a/elastic_transport/_node/_urllib3_chain_certs.py b/elastic_transport/_node/_urllib3_chain_certs.py
index 0d99896..e01f6a9 100644
--- a/elastic_transport/_node/_urllib3_chain_certs.py
+++ b/elastic_transport/_node/_urllib3_chain_certs.py
@@ -36,7 +36,17 @@ _HASHES_BY_LENGTH = {32: hashlib.md5, 40: hashlib.sha1, 64: hashlib.sha256}
__all__ = ["HTTPSConnectionPool"]
+class HTTPSConnection(urllib3.connection.HTTPSConnection):
+ def connect(self) -> None:
+ super().connect()
+ # Hack to prevent a warning within HTTPSConnectionPool._validate_conn()
+ if self._elastic_assert_fingerprint:
+ self.is_verified = True
+
+
class HTTPSConnectionPool(urllib3.HTTPSConnectionPool):
+ ConnectionCls = HTTPSConnection
+
"""HTTPSConnectionPool implementation which supports ``assert_fingerprint``
on certificates within the chain instead of only the leaf cert using private
APIs in CPython 3.10+
@@ -60,13 +70,21 @@ class HTTPSConnectionPool(urllib3.HTTPSConnectionPool):
f", should be one of '{valid_lengths}'"
)
- if assert_fingerprint:
- # Falsey but not None. This is a hack to skip fingerprinting by urllib3
- # but still set 'is_verified=True' within HTTPSConnectionPool._validate_conn()
- kwargs["assert_fingerprint"] = ""
+ if self._elastic_assert_fingerprint:
+ # Skip fingerprinting by urllib3 as we'll do it ourselves
+ kwargs["assert_fingerprint"] = None
super().__init__(*args, **kwargs)
+ def _new_conn(self) -> HTTPSConnection:
+ """
+ Return a fresh :class:`urllib3.connection.HTTPSConnection`.
+ """
+ conn = super()._new_conn()
+ # Tell our custom connection if we'll assert fingerprint ourselves
+ conn._elastic_assert_fingerprint = self._elastic_assert_fingerprint
+ return conn
+
def _validate_conn(self, conn: urllib3.connection.HTTPSConnection) -> None:
"""
Called right before a request is made, after the socket is created. |
This should be fixed in #121 , just merged. |
Closes #102