Skip to content

Commit afde445

Browse files
committed
Add client certificates support to async library
1 parent 9d6775e commit afde445

File tree

4 files changed

+27
-50
lines changed

4 files changed

+27
-50
lines changed

examples/basic/sample.py

Lines changed: 0 additions & 44 deletions
This file was deleted.

mygeotab/api.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,8 @@ def _query(server, method, parameters, timeout=DEFAULT_TIMEOUT, verify_ssl=True,
332332
:type verify_ssl: bool
333333
:param proxies: The proxies dictionary to apply to the request.
334334
:type proxies: dict or None
335+
:param cert: The path to client certificate. A single path to .pem file or a Tuple (.cer file, .pem file)
336+
:type cert: str or Tuple or None
335337
:raise MyGeotabException: Raises when an exception occurs on the MyGeotab server.
336338
:raise TimeoutException: Raises when the request does not respond after some time.
337339
:raise urllib2.HTTPError: Raises when there is an HTTP status code that indicates failure.

mygeotab/py3/api_async.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ def __init__(
3535
server="my.geotab.com",
3636
timeout=DEFAULT_TIMEOUT,
3737
proxies=None,
38+
cert=None
3839
):
3940
"""
4041
Initialize the asynchronous MyGeotab API object with credentials.
@@ -46,9 +47,10 @@ def __init__(
4647
:param server: The server ie. my23.geotab.com. Optional as this usually gets resolved upon authentication.
4748
:param timeout: The timeout to make the call, in seconds. By default, this is 300 seconds (or 5 minutes).
4849
:param proxies: The proxies dictionary to apply to the request.
50+
:param cert: The path to client certificate. A single path to .pem file or a Tuple (.cer file, .pem file)
4951
:raise Exception: Raises an Exception if a username, or one of the session_id or password is not provided.
5052
"""
51-
super().__init__(username, password, database, session_id, server, timeout, proxies=proxies)
53+
super().__init__(username, password, database, session_id, server, timeout, proxies=proxies, cert=cert)
5254

5355
async def call_async(self, method, **parameters):
5456
"""Makes an async call to the API.
@@ -68,7 +70,7 @@ async def call_async(self, method, **parameters):
6870
params["credentials"] = self.credentials.get_param()
6971

7072
try:
71-
result = await _query(self._server, method, params, verify_ssl=self._is_verify_ssl)
73+
result = await _query(self._server, method, params, verify_ssl=self._is_verify_ssl, cert=self._cert)
7274
if result is not None:
7375
self.__reauthorize_count = 0
7476
return result
@@ -181,14 +183,15 @@ async def server_call_async(method, server, timeout=DEFAULT_TIMEOUT, verify_ssl=
181183
return await _query(server, method, parameters, timeout=timeout, verify_ssl=verify_ssl)
182184

183185

184-
async def _query(server, method, parameters, timeout=DEFAULT_TIMEOUT, verify_ssl=True):
186+
async def _query(server, method, parameters, timeout=DEFAULT_TIMEOUT, verify_ssl=True, cert=None):
185187
"""Formats and performs the asynchronous query against the API
186188
187189
:param server: The server to query.
188190
:param method: The method name.
189191
:param parameters: A dict of parameters to send
190192
:param timeout: The timeout to make the call, in seconds. By default, this is 300 seconds (or 5 minutes).
191193
:param verify_ssl: Whether or not to verify SSL connections
194+
:param cert: The path to client certificate. A single path to .pem file or a Tuple (.cer file, .pem file)
192195
:return: The JSON-decoded result from the server
193196
:raise MyGeotabException: Raises when an exception occurs on the MyGeotab server
194197
:raise TimeoutException: Raises when the request does not respond after some time.
@@ -197,7 +200,18 @@ async def _query(server, method, parameters, timeout=DEFAULT_TIMEOUT, verify_ssl
197200
api_endpoint = api.get_api_url(server)
198201
params = dict(id=-1, method=method, params=parameters)
199202
headers = get_headers()
200-
conn = aiohttp.TCPConnector(ssl=ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) if verify_ssl else False)
203+
204+
ssl_context = False
205+
if verify_ssl or cert:
206+
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
207+
if cert:
208+
if isinstance(cert, str):
209+
ssl_context.load_cert_chain(cert)
210+
elif isinstance(cert, tuple):
211+
cer, key = cert
212+
ssl_context.load_cert_chain(cer, key)
213+
214+
conn = aiohttp.TCPConnector(ssl=ssl_context)
201215
try:
202216
async with aiohttp.ClientSession(connector=conn) as session:
203217
response = await session.post(

tests/test_api_async.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from mygeotab import API, server_call_async
1010
from mygeotab.exceptions import MyGeotabException, TimeoutException
11-
from tests.test_api_call import SERVER, USERNAME, PASSWORD, DATABASE, TRAILER_NAME
11+
from tests.test_api_call import SERVER, USERNAME, PASSWORD, DATABASE, CER_FILE, KEY_FILE, PEM_FILE, TRAILER_NAME
1212

1313
ASYNC_TRAILER_NAME = "async {name}".format(name=TRAILER_NAME)
1414

@@ -20,8 +20,13 @@
2020

2121
@pytest.fixture(scope="session")
2222
def async_populated_api():
23+
cert = None
24+
if CER_FILE and KEY_FILE:
25+
cert = (CER_FILE, KEY_FILE)
26+
elif PEM_FILE:
27+
cert = PEM_FILE
2328
if USERNAME and PASSWORD:
24-
session = API(USERNAME, password=PASSWORD, database=DATABASE, server=SERVER)
29+
session = API(USERNAME, password=PASSWORD, database=DATABASE, server=SERVER, cert=cert)
2530
try:
2631
session.authenticate()
2732
except MyGeotabException as exception:

0 commit comments

Comments
 (0)