Skip to content

Commit 5900f26

Browse files
author
Bilal Al
committed
refactored httpclient for kerberos auth
1 parent 38bd316 commit 5900f26

File tree

3 files changed

+166
-71
lines changed

3 files changed

+166
-71
lines changed

splitio/api/client.py

Lines changed: 134 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def _get_headers(self, extra_headers, sdk_key):
122122
class HttpClient(HttpClientBase):
123123
"""HttpClient wrapper."""
124124

125-
def __init__(self, timeout=None, sdk_url=None, events_url=None, auth_url=None, telemetry_url=None, authentication_scheme=None, authentication_params=None):
125+
def __init__(self, timeout=None, sdk_url=None, events_url=None, auth_url=None, telemetry_url=None):
126126
"""
127127
Class constructor.
128128
@@ -140,8 +140,6 @@ def __init__(self, timeout=None, sdk_url=None, events_url=None, auth_url=None, t
140140
_LOGGER.debug("Initializing httpclient")
141141
self._timeout = timeout/1000 if timeout else None # Convert ms to seconds.
142142
self._urls = _construct_urls(sdk_url, events_url, auth_url, telemetry_url)
143-
self._authentication_scheme = authentication_scheme
144-
self._authentication_params = authentication_params
145143
self._lock = threading.RLock()
146144

147145
def get(self, server, path, sdk_key, query=None, extra_headers=None): # pylint: disable=too-many-arguments
@@ -164,20 +162,18 @@ def get(self, server, path, sdk_key, query=None, extra_headers=None): # pylint:
164162
"""
165163
with self._lock:
166164
start = get_current_epoch_time_ms()
167-
with requests.Session() as session:
168-
self._set_authentication(session)
169-
try:
170-
response = session.get(
171-
_build_url(server, path, self._urls),
172-
params=query,
173-
headers=self._get_headers(extra_headers, sdk_key),
174-
timeout=self._timeout
175-
)
176-
self._record_telemetry(response.status_code, get_current_epoch_time_ms() - start)
177-
return HttpResponse(response.status_code, response.text, response.headers)
178-
179-
except Exception as exc: # pylint: disable=broad-except
180-
raise HttpClientException('requests library is throwing exceptions') from exc
165+
try:
166+
response = requests.get(
167+
_build_url(server, path, self._urls),
168+
params=query,
169+
headers=self._get_headers(extra_headers, sdk_key),
170+
timeout=self._timeout
171+
)
172+
self._record_telemetry(response.status_code, get_current_epoch_time_ms() - start)
173+
return HttpResponse(response.status_code, response.text, response.headers)
174+
175+
except Exception as exc: # pylint: disable=broad-except
176+
raise HttpClientException('requests library is throwing exceptions') from exc
181177

182178
def post(self, server, path, sdk_key, body, query=None, extra_headers=None): # pylint: disable=too-many-arguments
183179
"""
@@ -201,35 +197,18 @@ def post(self, server, path, sdk_key, body, query=None, extra_headers=None): #
201197
"""
202198
with self._lock:
203199
start = get_current_epoch_time_ms()
204-
with requests.Session() as session:
205-
self._set_authentication(session)
206-
try:
207-
response = session.post(
208-
_build_url(server, path, self._urls),
209-
json=body,
210-
params=query,
211-
headers=self._get_headers(extra_headers, sdk_key),
212-
timeout=self._timeout,
213-
)
214-
self._record_telemetry(response.status_code, get_current_epoch_time_ms() - start)
215-
return HttpResponse(response.status_code, response.text, response.headers)
216-
except Exception as exc: # pylint: disable=broad-except
217-
raise HttpClientException('requests library is throwing exceptions') from exc
218-
219-
def _set_authentication(self, session):
220-
if self._authentication_scheme == AuthenticateScheme.KERBEROS_SPNEGO:
221-
_LOGGER.debug("Using Kerberos Spnego Authentication")
222-
if self._authentication_params != [None, None]:
223-
session.auth = HTTPKerberosAuth(principal=self._authentication_params[0], password=self._authentication_params[1], mutual_authentication=OPTIONAL)
224-
else:
225-
session.auth = HTTPKerberosAuth(mutual_authentication=OPTIONAL)
226-
elif self._authentication_scheme == AuthenticateScheme.KERBEROS_PROXY:
227-
_LOGGER.debug("Using Kerberos Proxy Authentication")
228-
if self._authentication_params != [None, None]:
229-
session.mount('https://', HTTPAdapterWithProxyKerberosAuth(principal=self._authentication_params[0], password=self._authentication_params[1]))
230-
else:
231-
session.mount('https://', HTTPAdapterWithProxyKerberosAuth())
232-
200+
try:
201+
response = requests.post(
202+
_build_url(server, path, self._urls),
203+
json=body,
204+
params=query,
205+
headers=self._get_headers(extra_headers, sdk_key),
206+
timeout=self._timeout,
207+
)
208+
self._record_telemetry(response.status_code, get_current_epoch_time_ms() - start)
209+
return HttpResponse(response.status_code, response.text, response.headers)
210+
except Exception as exc: # pylint: disable=broad-except
211+
raise HttpClientException('requests library is throwing exceptions') from exc
233212

234213
def _record_telemetry(self, status_code, elapsed):
235214
"""
@@ -372,3 +351,112 @@ async def _record_telemetry(self, status_code, elapsed):
372351
async def close_session(self):
373352
if not self._session.closed:
374353
await self._session.close()
354+
355+
class HttpClientKerberos(HttpClient):
356+
"""HttpClient wrapper."""
357+
358+
def __init__(self, timeout=None, sdk_url=None, events_url=None, auth_url=None, telemetry_url=None, authentication_scheme=None, authentication_params=None):
359+
"""
360+
Class constructor.
361+
362+
:param timeout: How many milliseconds to wait until the server responds.
363+
:type timeout: int
364+
:param sdk_url: Optional alternative sdk URL.
365+
:type sdk_url: str
366+
:param events_url: Optional alternative events URL.
367+
:type events_url: str
368+
:param auth_url: Optional alternative auth URL.
369+
:type auth_url: str
370+
:param telemetry_url: Optional alternative telemetry URL.
371+
:type telemetry_url: str
372+
"""
373+
_LOGGER.debug("Initializing httpclient for Kerberos auth")
374+
HttpClient.__init__(self, timeout, sdk_url, events_url, auth_url, telemetry_url)
375+
self._authentication_scheme = authentication_scheme
376+
self._authentication_params = authentication_params
377+
378+
def get(self, server, path, sdk_key, query=None, extra_headers=None): # pylint: disable=too-many-arguments
379+
"""
380+
Issue a get request.
381+
382+
:param server: Whether the request is for SDK server, Events server or Auth server.
383+
:typee server: str
384+
:param path: path to append to the host url.
385+
:type path: str
386+
:param sdk_key: sdk key.
387+
:type sdk_key: str
388+
:param query: Query string passed as dictionary.
389+
:type query: dict
390+
:param extra_headers: key/value pairs of possible extra headers.
391+
:type extra_headers: dict
392+
393+
:return: Tuple of status_code & response text
394+
:rtype: HttpResponse
395+
"""
396+
with self._lock:
397+
start = get_current_epoch_time_ms()
398+
with requests.Session() as session:
399+
self._set_authentication(session)
400+
try:
401+
response = session.get(
402+
_build_url(server, path, self._urls),
403+
params=query,
404+
headers=self._get_headers(extra_headers, sdk_key),
405+
timeout=self._timeout
406+
)
407+
self._record_telemetry(response.status_code, get_current_epoch_time_ms() - start)
408+
return HttpResponse(response.status_code, response.text, response.headers)
409+
410+
except Exception as exc: # pylint: disable=broad-except
411+
raise HttpClientException('requests library is throwing exceptions') from exc
412+
413+
def post(self, server, path, sdk_key, body, query=None, extra_headers=None): # pylint: disable=too-many-arguments
414+
"""
415+
Issue a POST request.
416+
417+
:param server: Whether the request is for SDK server or Events server.
418+
:typee server: str
419+
:param path: path to append to the host url.
420+
:type path: str
421+
:param sdk_key: sdk key.
422+
:type sdk_key: str
423+
:param body: body sent in the request.
424+
:type body: str
425+
:param query: Query string passed as dictionary.
426+
:type query: dict
427+
:param extra_headers: key/value pairs of possible extra headers.
428+
:type extra_headers: dict
429+
430+
:return: Tuple of status_code & response text
431+
:rtype: HttpResponse
432+
"""
433+
with self._lock:
434+
start = get_current_epoch_time_ms()
435+
with requests.Session() as session:
436+
self._set_authentication(session)
437+
try:
438+
response = session.post(
439+
_build_url(server, path, self._urls),
440+
json=body,
441+
params=query,
442+
headers=self._get_headers(extra_headers, sdk_key),
443+
timeout=self._timeout,
444+
)
445+
self._record_telemetry(response.status_code, get_current_epoch_time_ms() - start)
446+
return HttpResponse(response.status_code, response.text, response.headers)
447+
except Exception as exc: # pylint: disable=broad-except
448+
raise HttpClientException('requests library is throwing exceptions') from exc
449+
450+
def _set_authentication(self, session):
451+
if self._authentication_scheme == AuthenticateScheme.KERBEROS_SPNEGO:
452+
_LOGGER.debug("Using Kerberos Spnego Authentication")
453+
if self._authentication_params != [None, None]:
454+
session.auth = HTTPKerberosAuth(principal=self._authentication_params[0], password=self._authentication_params[1], mutual_authentication=OPTIONAL)
455+
else:
456+
session.auth = HTTPKerberosAuth(mutual_authentication=OPTIONAL)
457+
elif self._authentication_scheme == AuthenticateScheme.KERBEROS_PROXY:
458+
_LOGGER.debug("Using Kerberos Proxy Authentication")
459+
if self._authentication_params != [None, None]:
460+
session.mount('https://', HTTPAdapterWithProxyKerberosAuth(principal=self._authentication_params[0], password=self._authentication_params[1]))
461+
else:
462+
session.mount('https://', HTTPAdapterWithProxyKerberosAuth())

splitio/client/factory.py

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
PluggableImpressionsStorageAsync, PluggableSegmentStorageAsync, PluggableSplitStorageAsync
3434

3535
# APIs
36-
from splitio.api.client import HttpClient, HttpClientAsync
36+
from splitio.api.client import HttpClient, HttpClientAsync, HttpClientKerberos
3737
from splitio.api.splits import SplitsAPI, SplitsAPIAsync
3838
from splitio.api.segments import SegmentsAPI, SegmentsAPIAsync
3939
from splitio.api.impressions import ImpressionsAPI, ImpressionsAPIAsync
@@ -512,16 +512,23 @@ def _build_in_memory_factory(api_key, cfg, sdk_url=None, events_url=None, # pyl
512512
if cfg.get("httpAuthenticateScheme") in [AuthenticateScheme.KERBEROS_SPNEGO, AuthenticateScheme.KERBEROS_PROXY]:
513513
authentication_params = [cfg.get("kerberosPrincipalUser"),
514514
cfg.get("kerberosPrincipalPassword")]
515-
516-
http_client = HttpClient(
517-
sdk_url=sdk_url,
518-
events_url=events_url,
519-
auth_url=auth_api_base_url,
520-
telemetry_url=telemetry_api_base_url,
521-
timeout=cfg.get('connectionTimeout'),
522-
authentication_scheme = cfg.get("httpAuthenticateScheme"),
523-
authentication_params = authentication_params
524-
)
515+
http_client = HttpClientKerberos(
516+
sdk_url=sdk_url,
517+
events_url=events_url,
518+
auth_url=auth_api_base_url,
519+
telemetry_url=telemetry_api_base_url,
520+
timeout=cfg.get('connectionTimeout'),
521+
authentication_scheme = cfg.get("httpAuthenticateScheme"),
522+
authentication_params = authentication_params
523+
)
524+
else:
525+
http_client = HttpClient(
526+
sdk_url=sdk_url,
527+
events_url=events_url,
528+
auth_url=auth_api_base_url,
529+
telemetry_url=telemetry_api_base_url,
530+
timeout=cfg.get('connectionTimeout'),
531+
)
525532

526533
sdk_metadata = util.get_metadata(cfg)
527534
apis = {

0 commit comments

Comments
 (0)