8000 [Fix] Make overriding TLS verification optional (#202) · arangodb/python-arango@252abe2 · GitHub
[go: up one dir, main page]

Skip to content

Commit 252abe2

Browse files
authored
[Fix] Make overriding TLS verification optional (#202)
* [Fix] Make overriding TLS verification optional * Add tests
1 parent fd21695 commit 252abe2

File tree

4 files changed

+79
-12
lines changed

4 files changed

+79
-12
lines changed

arango/client.py

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,13 @@ class ArangoClient:
4545
the de-serialized object. If not given, ``json.loads`` is used by
4646
default.
4747
:type deserializer: callable
48-
:param verify_certificate: Verify TLS certificates.
49-
:type verify_certificate: bool
48+
:param verify_override: Override TLS certificate verification. This will
49+
override the verify method of the underlying HTTP client.
50+
None: Do not change the verification behavior of the underlying HTTP client.
51+
True: Verify TLS certificate using the system CA certificates.
52+
False: Do not verify TLS certificate.
53+
str: Path to a custom CA bundle file or directory.
54+
:type verify_override: Union[bool, str, None]
5055
"""
5156

5257
def __init__(
@@ -57,7 +62,7 @@ def __init__(
5762
http_client: Optional[HTTPClient] = None,
5863
serializer: Callable[..., str] = lambda x: dumps(x),
5964
deserializer: Callable[[str], Any] = lambda x: loads(x),
60-
verify_certificate: bool = True,
65+
verify_override: Union[bool, str, None] = None,
6166
) -> None:
6267
if isinstance(hosts, str):
6368
self._hosts = [host.strip("/") for host in hosts.split(",")]
@@ -79,9 +84,10 @@ def __init__(
7984
self._deserializer = deserializer
8085
self._sessions = [self._http.create_session(h) for h in self._hosts]
8186

82-
# set flag for SSL/TLS certificate verification
83-
for session in self._sessions:
84-
session.verify = verify_certificate
87+
# override SSL/TLS certificate verification if provided
88+
if verify_override is not None:
89+
for session in self._sessions:
90+
session.verify = verify_override
8591

8692
def __repr__(self) -> str:
8793
return f"<ArangoClient {','.join(self._hosts)}>"

docs/certificates.rst

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,20 @@ By default, self-signed certificates will cause trouble when connecting.
99
1010
client = ArangoClient(hosts="https://localhost:8529")
1111
12-
In order to make connections work even when using self-signed certificates, the
13-
`verify_certificates` option can be disabled when creating the `ArangoClient`
14-
instance:
12+
To make connections work even when using self-signed certificates, you can
13+
provide the certificate CA bundle or turn the verification off.
14+
15+
If you want to have fine-grained control over the HTTP connection, you should define
16+
your HTTP client as described in the :ref:`HTTPClients` section.
17+
18+
The ``ArangoClient`` class provides an option to override the verification behavior,
19+
no matter what has been defined in the underlying HTTP session.
20+
You can use this option to disable verification or provide a custom CA bundle without
21+
defining a custom HTTP Client.
1522

1623
.. code-block:: python
1724
18-
client = ArangoClient(hosts="https://localhost:8529", verify_certificate=False)
25+
client = ArangoClient(hosts="https://localhost:8529", verify_override=False)
1926
2027
This will allow connecting, but the underlying `urllib3` library may still issue
2128
warnings due to the insecurity of using self-signed certificates.
@@ -26,5 +33,4 @@ application:
2633
.. code-block:: python
2734
2835
import requests
29-
requests.packages.urllib3.disable_warnings()
30-
36+
requests.packages.urllib3.disable_warnings()

docs/http.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
.. _HTTPClients:
2+
13
HTTP Clients
24
------------
35

tests/test_client.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import json
2+
from typing import Union
23

34
import pytest
45
from pkg_resources import get_distribution
6+
from requests import Session
57

68
from arango.client import ArangoClient
79
from arango.database import StandardDatabase
@@ -108,3 +110,54 @@ def send_request(
108110
# Set verify to True to send a test API call on initialization.
109111
client.db(db.name, username, password, verify=True)
110112
assert http_client.counter == 1
113+
114+
115+
def test_client_override_validate() -> None:
116+
# custom http client that manipulates the underlying session
117+
class MyHTTPClient(DefaultHTTPClient):
118+
def __init__(self, verify: Union[None, bool, str]) -> None:
119+
super().__init__()
120+
self.verify = verify
121+
122+
def create_session(self, host: str) -> Session:
123+
session = super().create_session(host)
124+
session.verify = self.verify
125+
return session
126+
127+
def assert_verify(
128+
http_client_verify: Union[None, str, bool],
129+
arango_override: Union[None, str, bool],
130+
expected_result: Union[None, str, bool],
131+
) -> None:
132+
http_client = MyHTTPClient(verify=http_client_verify)
133+
client = ArangoClient(
134+
hosts="http://127.0.0.1:8529",
135+
http_client=http_client,
136+
verify_override=arango_override,
137+
)
138+
# make sure there is at least 1 session
139+
assert len(client._sessions) > 0
140+
for session in client._sessions:
141+
# make sure the final session.verify has expected value
142+
assert session.verify == expected_result
143+
144+
assert_verify(None, None, None)
145+
assert_verify(None, True, True)
146+
assert_verify(None, False, False)
147+
assert_verify(None, "test", "test")
148+
149+
assert_verify(True, None, True)
150+
assert_verify(True, True, True)
151+
assert_verify(True, "test", "test")
152+
assert_verify(True, False, False)
153+
154+
assert_verify(False, None, False)
155+
assert_verify(False, True, True)
156+
assert_verify(False, "test", "test")
157+
assert_verify(False, False, False)
158+
159+
assert_verify("test", None, "test")
160+
assert_verify("test", True, True)
161+
assert_verify("test", False, False)
162+
assert_verify("test", False, False)
163+
assert_verify("test", "foo", "foo")

0 commit comments

Comments
 (0)
0