Skip to content

Commit 8dcdeaf

Browse files
committed
Sem-Ver: api-break Optimise the standard requests session based public key retrieval by obtaining proxy information from the environment once per a public key server and setting session.trust_env to False.
As a result of this change retrieving the same public key, with caching enabled, 10,000 times takes ~ 6 seconds instead of ~ 14 seconds. Signed-off-by: David Black <[email protected]>
1 parent acceeb9 commit 8dcdeaf

File tree

2 files changed

+79
-1
lines changed

2 files changed

+79
-1
lines changed

atlassian_jwt_auth/key.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import cryptography.hazmat.backends
1010
import jwt
1111
import requests
12+
import requests.utils
1213
from cryptography.hazmat.primitives import serialization
1314
from requests.exceptions import RequestException, ConnectionError
1415

@@ -84,18 +85,21 @@ def __init__(self, base_url):
8485
base_url += '/'
8586
self.base_url = base_url
8687
self._session = self._get_session()
88+
self._proxies = requests.utils.get_environ_proxies(self.base_url)
8789

8890
def _get_session(self):
8991
if HTTPSPublicKeyRetriever._class_session is None:
9092
session = cachecontrol.CacheControl(requests.Session())
93+
session.trust_env = False
9194
HTTPSPublicKeyRetriever._class_session = session
9295
return HTTPSPublicKeyRetriever._class_session
9396

9497
def retrieve(self, key_identifier, **requests_kwargs):
9598
""" returns the public key for given key_identifier. """
9699
if not isinstance(key_identifier, KeyIdentifier):
97100
key_identifier = KeyIdentifier(key_identifier)
98-
101+
if self._proxies and 'proxies' not in requests_kwargs:
102+
requests_kwargs['proxies'] = self._proxies
99103
url = self.base_url + key_identifier.key_id
100104
try:
101105
return self._retrieve(url, requests_kwargs)

atlassian_jwt_auth/tests/test_public_key_provider.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import os
12
import re
23
import unittest
34

@@ -8,10 +9,26 @@
89
from atlassian_jwt_auth.key import (
910
HTTPSPublicKeyRetriever,
1011
HTTPSMultiRepositoryPublicKeyRetriever,
12+
PEM_FILE_TYPE,
1113
)
1214
from atlassian_jwt_auth.tests import utils
1315

1416

17+
def get_expected_and_os_proxies_dict(proxy_location):
18+
""" returns expected proxy & environmental
19+
proxy dictionary based upon the provided proxy location.
20+
"""
21+
expected_proxies = {
22+
'http': proxy_location,
23+
'https': proxy_location,
24+
}
25+
os_proxy_dict = {
26+
'HTTP_PROXY': proxy_location,
27+
'HTTPS_PROXY': proxy_location
28+
}
29+
return expected_proxies, os_proxy_dict
30+
31+
1532
class BaseHTTPSPublicKeyRetrieverTest(object):
1633
""" tests for the HTTPSPublicKeyRetriever class. """
1734

@@ -39,6 +56,21 @@ def test_https_public_key_retriever_does_not_support_none_url(self):
3956
with self.assertRaises(ValueError):
4057
self.create_retriever(None)
4158

59+
def test_https_public_key_retriever_session_uses_env_proxy(self):
60+
""" tests that the underlying session makes use of environmental
61+
proxy configured.
62+
"""
63+
proxy_location = 'https://example.proxy'
64+
expected_proxies, proxy_dict = get_expected_and_os_proxies_dict(
65+
proxy_location)
66+
with mock.patch.dict(os.environ, proxy_dict, clear=True):
67+
retriever = self.create_retriever(self.base_url)
68+
key_retrievers = [retriever]
69+
if isinstance(retriever, HTTPSMultiRepositoryPublicKeyRetriever):
70+
key_retrievers = retriever._retrievers
71+
for key_retriever in key_retrievers:
72+
self.assertEqual(key_retriever._proxies, expected_proxies)
73+
4274
def test_https_public_key_retriever_supports_https_url(self):
4375
""" tests that HTTPSPublicKeyRetriever supports https://
4476
base urls.
@@ -55,6 +87,48 @@ def test_retrieve(self, mock_get_method):
5587
retriever.retrieve('example/eg'),
5688
self._public_key_pem)
5789

90+
@mock.patch.object(requests.Session, 'get')
91+
def test_retrieve_with_proxy(self, mock_get_method):
92+
""" tests that the retrieve method works as expected when a proxy
93+
should be used.
94+
"""
95+
proxy_location = 'https://example.proxy'
96+
key_id = 'example/eg'
97+
expected_proxies, proxy_dict = get_expected_and_os_proxies_dict(
98+
proxy_location)
99+
_setup_mock_response_for_retriever(
100+
mock_get_method, self._public_key_pem)
101+
with mock.patch.dict(os.environ, proxy_dict, clear=True):
102+
retriever = self.create_retriever(self.base_url)
103+
retriever.retrieve(key_id)
104+
mock_get_method.assert_called_once_with(
105+
'%s/%s' % (self.base_url, key_id),
106+
headers={'accept': PEM_FILE_TYPE},
107+
proxies=expected_proxies
108+
)
109+
110+
@mock.patch.object(requests.Session, 'get')
111+
def test_retrieve_with_proxy_explicitly_set(self, mock_get_method):
112+
""" tests that the retrieve method works as expected when a proxy
113+
should be used and has been explicitly provided.
114+
"""
115+
proxy_location = 'https://example.proxy'
116+
explicit_proxy_location = 'https://explicit.proxy'
117+
key_id = 'example/eg'
118+
_, proxy_dict = get_expected_and_os_proxies_dict(proxy_location)
119+
expected_proxies, _ = get_expected_and_os_proxies_dict(
120+
explicit_proxy_location)
121+
_setup_mock_response_for_retriever(
122+
mock_get_method, self._public_key_pem)
123+
with mock.patch.dict(os.environ, proxy_dict, clear=True):
124+
retriever = self.create_retriever(self.base_url)
125+
retriever.retrieve(key_id, proxies=expected_proxies)
126+
mock_get_method.assert_called_once_with(
127+
'%s/%s' % (self.base_url, key_id),
128+
headers={'accept': PEM_FILE_TYPE},
129+
proxies=expected_proxies
130+
)
131+
58132
@mock.patch.object(requests.Session, 'get')
59133
def test_retrieve_with_charset_in_content_type_h(self, mock_get_method):
60134
""" tests that the retrieve method works expected when there is

0 commit comments

Comments
 (0)