summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRatan Kulshreshtha <ratan.shreshtha@gmail.com>2019-05-25 03:13:49 +0530
committerRatan Kulshreshtha <ratan.shreshtha@gmail.com>2019-05-25 03:13:49 +0530
commitd8a63d0ae7b89d69709309fdbd038a414a5ec63e (patch)
tree7c692cde117be7a5414695c7a64508459bc79819
parent266b347d393a16684f2b5abb87aeb5b13ca4f0b7 (diff)
parent337992aba77104fb84e7b14f5a2c9aa1d3039415 (diff)
downloadurllib3-d8a63d0ae7b89d69709309fdbd038a414a5ec63e.tar.gz
Merge branch 'master' into blacken
-rw-r--r--.github/FUNDING.yml1
-rw-r--r--CHANGES.rst10
-rw-r--r--docs/contributing.rst4
-rw-r--r--src/urllib3/__init__.py2
-rw-r--r--src/urllib3/connection.py31
-rw-r--r--test/with_dummyserver/test_socketlevel.py88
6 files changed, 129 insertions, 7 deletions
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 00000000..554e65fb
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+tidelift: pypi/urllib3
diff --git a/CHANGES.rst b/CHANGES.rst
index 09409b66..a7724471 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,10 +1,14 @@
Changes
=======
-dev (master)
-------------
+1.25.3 (2019-05-23)
+-------------------
+
+* Change ``HTTPSConnection`` to load system CA certificates
+ when ``ca_certs``, ``ca_cert_dir``, and ``ssl_context`` are
+ unspecified. (Pull #1608, Issue #1603)
-* Upgrade bundled rfc3986 to 1.3.2. (Pull #1609, Issue #1605)
+* Upgrade bundled rfc3986 to v1.3.2. (Pull #1609, Issue #1605)
1.25.2 (2019-04-28)
diff --git a/docs/contributing.rst b/docs/contributing.rst
index 39e47d7e..c28bc479 100644
--- a/docs/contributing.rst
+++ b/docs/contributing.rst
@@ -77,8 +77,8 @@ named ``release-x.x`` where ``x.x`` is the version of the proposed release.
- Integration tests are run against the release candidate on Travis. From here on all
the steps below will be handled by a maintainer so unless you receive review comments
you are done here.
-- Once the pull request is squash merged into master the merging maintainer the
- pull request will tag the merge commit with the version number:
+- Once the pull request is squash merged into master the merging maintainer
+ will tag the merge commit with the version number:
- ``git tag -a 1.24.1 [commit sha]``
- ``git push origin master --tags``
diff --git a/src/urllib3/__init__.py b/src/urllib3/__init__.py
index 5a23d503..63e5026f 100644
--- a/src/urllib3/__init__.py
+++ b/src/urllib3/__init__.py
@@ -22,7 +22,7 @@ from logging import NullHandler
__author__ = "Andrey Petrov (andrey.petrov@shazow.net)"
__license__ = "MIT"
-__version__ = "1.25.2"
+__version__ = "1.25.3"
__all__ = (
"HTTPConnectionPool",
diff --git a/src/urllib3/connection.py b/src/urllib3/connection.py
index 94e95c67..f0396f25 100644
--- a/src/urllib3/connection.py
+++ b/src/urllib3/connection.py
@@ -257,11 +257,27 @@ class HTTPSConnection(HTTPConnection):
conn = self._new_conn()
self._prepare_conn(conn)
+ # Wrap socket using verification with the root certs in
+ # trusted_root_certs
+ default_ssl_context = False
if self.ssl_context is None:
+ default_ssl_context = True
self.ssl_context = create_urllib3_context(
- ssl_version=resolve_ssl_version(None), cert_reqs=resolve_cert_reqs(None)
+ ssl_version=resolve_ssl_version(self.ssl_version),
+ cert_reqs=resolve_cert_reqs(self.cert_reqs),
)
+ # Try to load OS default certs if none are given.
+ # Works well on Windows (requires Python3.4+)
+ context = self.ssl_context
+ if (
+ not self.ca_certs
+ and not self.ca_cert_dir
+ and default_ssl_context
+ and hasattr(context, "load_default_certs")
+ ):
+ context.load_default_certs()
+
self.sock = ssl_wrap_socket(
sock=conn,
keyfile=self.key_file,
@@ -348,7 +364,9 @@ class VerifiedHTTPSConnection(HTTPSConnection):
# Wrap socket using verification with the root certs in
# trusted_root_certs
+ default_ssl_context = False
if self.ssl_context is None:
+ default_ssl_context = True
self.ssl_context = create_urllib3_context(
ssl_version=resolve_ssl_version(self.ssl_version),
cert_reqs=resolve_cert_reqs(self.cert_reqs),
@@ -356,6 +374,17 @@ class VerifiedHTTPSConnection(HTTPSConnection):
context = self.ssl_context
context.verify_mode = resolve_cert_reqs(self.cert_reqs)
+
+ # Try to load OS default certs if none are given.
+ # Works well on Windows (requires Python3.4+)
+ if (
+ not self.ca_certs
+ and not self.ca_cert_dir
+ and default_ssl_context
+ and hasattr(context, "load_default_certs")
+ ):
+ context.load_default_certs()
+
self.sock = ssl_wrap_socket(
sock=conn,
keyfile=self.key_file,
diff --git a/test/with_dummyserver/test_socketlevel.py b/test/with_dummyserver/test_socketlevel.py
index 30e7ee75..76637a38 100644
--- a/test/with_dummyserver/test_socketlevel.py
+++ b/test/with_dummyserver/test_socketlevel.py
@@ -41,6 +41,7 @@ from threading import Event
import select
import socket
import ssl
+import mock
import pytest
@@ -1331,6 +1332,93 @@ class TestSSL(SocketDummyServerTestCase):
response = pool.urlopen("GET", "/", retries=1)
self.assertEqual(response.data, b"Success")
+ def test_ssl_load_default_certs_when_empty(self):
+ def socket_handler(listener):
+ sock = listener.accept()[0]
+ ssl_sock = ssl.wrap_socket(
+ sock,
+ server_side=True,
+ keyfile=DEFAULT_CERTS["keyfile"],
+ certfile=DEFAULT_CERTS["certfile"],
+ ca_certs=DEFAULT_CA,
+ )
+
+ buf = b""
+ while not buf.endswith(b"\r\n\r\n"):
+ buf += ssl_sock.recv(65536)
+
+ ssl_sock.send(
+ b"HTTP/1.1 200 OK\r\n"
+ b"Content-Type: text/plain\r\n"
+ b"Content-Length: 5\r\n\r\n"
+ b"Hello"
+ )
+
+ ssl_sock.close()
+ sock.close()
+
+ context = mock.create_autospec(ssl_.SSLContext)
+ context.load_default_certs = mock.Mock()
+ context.options = 0
+
+ with mock.patch("urllib3.util.ssl_.SSLContext", lambda *_, **__: context):
+
+ self._start_server(socket_handler)
+ pool = HTTPSConnectionPool(self.host, self.port)
+ self.addCleanup(pool.close)
+
+ with self.assertRaises(MaxRetryError):
+ pool.request("GET", "/", timeout=0.01)
+
+ context.load_default_certs.assert_called_with()
+
+ def test_ssl_dont_load_default_certs_when_given(self):
+ def socket_handler(listener):
+ sock = listener.accept()[0]
+ ssl_sock = ssl.wrap_socket(
+ sock,
+ server_side=True,
+ keyfile=DEFAULT_CERTS["keyfile"],
+ certfile=DEFAULT_CERTS["certfile"],
+ ca_certs=DEFAULT_CA,
+ )
+
+ buf = b""
+ while not buf.endswith(b"\r\n\r\n"):
+ buf += ssl_sock.recv(65536)
+
+ ssl_sock.send(
+ b"HTTP/1.1 200 OK\r\n"
+ b"Content-Type: text/plain\r\n"
+ b"Content-Length: 5\r\n\r\n"
+ b"Hello"
+ )
+
+ ssl_sock.close()
+ sock.close()
+
+ context = mock.create_autospec(ssl_.SSLContext)
+ context.load_default_certs = mock.Mock()
+ context.options = 0
+
+ with mock.patch("urllib3.util.ssl_.SSLContext", lambda *_, **__: context):
+ for kwargs in [
+ {"ca_certs": "/a"},
+ {"ca_cert_dir": "/a"},
+ {"ca_certs": "a", "ca_cert_dir": "a"},
+ {"ssl_context": context},
+ ]:
+
+ self._start_server(socket_handler)
+
+ pool = HTTPSConnectionPool(self.host, self.port, **kwargs)
+ self.addCleanup(pool.close)
+
+ with self.assertRaises(MaxRetryError):
+ pool.request("GET", "/", timeout=0.01)
+
+ context.load_default_certs.assert_not_called()
+
class TestErrorWrapping(SocketDummyServerTestCase):
def test_bad_statusline(self):