Skip to content

Commit 737ce9f

Browse files
authored
Merge pull request #32 from chkp-royl/master
Add support to use single https connection
2 parents 007984e + c92f5dc commit 737ce9f

File tree

1 file changed

+53
-39
lines changed

1 file changed

+53
-39
lines changed

cpapi/mgmt_api.py

Lines changed: 53 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@ class APIClientArgs:
3838

3939
# port is set to None by default, but it gets replaced with 443 if not specified
4040
# context possible values - web_api (default) or gaia_api
41+
# single_conn is set to True by default, when work on parallel set to False
4142
def __init__(self, port=None, fingerprint=None, sid=None, server="127.0.0.1", http_debug_level=0,
4243
api_calls=None, debug_file="", proxy_host=None, proxy_port=8080,
43-
api_version=None, unsafe=False, unsafe_auto_accept=False, context="web_api"):
44+
api_version=None, unsafe=False, unsafe_auto_accept=False, context="web_api", single_conn=True):
4445
self.port = port
4546
# management server fingerprint
4647
self.fingerprint = fingerprint
@@ -66,6 +67,8 @@ def __init__(self, port=None, fingerprint=None, sid=None, server="127.0.0.1", ht
6667
self.unsafe_auto_accept = unsafe_auto_accept
6768
# The context of using the client - defaults to web_api
6869
self.context = context
70+
# Indicates that the client should use single HTTPS connection
71+
self.single_conn = single_conn
6972

7073

7174
class APIClient:
@@ -108,6 +111,10 @@ def __init__(self, api_client_args=None):
108111
self.unsafe_auto_accept = api_client_args.unsafe_auto_accept
109112
# The context of using the client - defaults to web_api
110113
self.context = api_client_args.context
114+
# HTTPS connection
115+
self.conn = None
116+
# Indicates that the client should use single HTTPS connection
117+
self.single_conn = api_client_args.single_conn
111118

112119
def __enter__(self):
113120
return self
@@ -117,6 +124,7 @@ def __exit__(self, exc_type, exc_value, traceback):
117124
# if sid is not empty (the login api was called), then call logout
118125
if self.sid:
119126
self.api_call("logout")
127+
self.close_connection()
120128
# save debug data with api calls to disk
121129
self.save_debug_data()
122130

@@ -265,8 +273,8 @@ def api_call(self, command, payload=None, sid=None, wait_for_task=True, timeout=
265273
:side-effects: updates the class's uid and server variables
266274
"""
267275
timeout_start = time.time()
268-
269-
self.check_fingerprint()
276+
if self.check_fingerprint() is False:
277+
return APIResponse("", False, err_message="Invalid fingerprint")
270278
if payload is None:
271279
payload = {}
272280
# Convert the json payload to a string if needed
@@ -292,23 +300,8 @@ def api_call(self, command, payload=None, sid=None, wait_for_task=True, timeout=
292300
if sid is not None:
293301
_headers["X-chkp-sid"] = sid
294302

295-
# Create ssl context with no ssl verification, we do it by ourselves
296-
context = ssl.create_default_context()
297-
context.check_hostname = False
298-
context.verify_mode = ssl.CERT_NONE
299-
300-
# create https connection
301-
if self.proxy_host and self.proxy_port:
302-
conn = HTTPSConnection(self.proxy_host, self.proxy_port, context=context)
303-
conn.set_tunnel(self.server, self.get_port())
304-
else:
305-
conn = HTTPSConnection(self.server, self.get_port(), context=context)
306-
307-
# Set fingerprint
308-
conn.fingerprint = self.fingerprint
309-
310-
# Set debug level
311-
conn.set_debuglevel(self.http_debug_level)
303+
# init https connection. if single connection is True, use last connection
304+
conn = self.get_https_connection()
312305
url = "/" + self.context + "/" + (("v" + str(self.api_version) + "/") if self.api_version else "") + command
313306
response = None
314307
try:
@@ -328,7 +321,8 @@ def api_call(self, command, payload=None, sid=None, wait_for_task=True, timeout=
328321
except Exception as err:
329322
res = APIResponse("", False, err_message=err)
330323
finally:
331-
conn.close()
324+
if not self.single_conn:
325+
conn.close()
332326

333327
if response:
334328
res.status_code = response.status
@@ -464,21 +458,13 @@ def gen_api_query(self, command, details_level="standard", container_keys=None,
464458

465459
def get_server_fingerprint(self):
466460
"""
467-
Initiates an HTTPS connection to the server and extracts the SHA1 fingerprint from the server's certificate.
461+
Initiates an HTTPS connection to the server if need and extracts the SHA1 fingerprint from the server's certificate.
468462
:return: string with SHA1 fingerprint (all uppercase letters)
469463
"""
470-
context = ssl.create_default_context()
471-
context.check_hostname = False
472-
context.verify_mode = ssl.CERT_NONE
473-
474-
if self.proxy_host and self.proxy_port:
475-
conn = HTTPSConnection(self.proxy_host, self.proxy_port, context=context)
476-
conn.set_tunnel(self.server, self.get_port())
477-
else:
478-
conn = HTTPSConnection(self.server, self.get_port(), context=context)
479-
464+
conn = self.get_https_connection(set_fingerprint=False, set_debug_level=False)
480465
fingerprint_hash = conn.get_fingerprint_hash()
481-
conn.close()
466+
if not self.single_conn:
467+
conn.close()
482468
return fingerprint_hash
483469

484470
def __wait_for_task(self, task_id, timeout=-1):
@@ -723,22 +709,50 @@ def read_fingerprint_from_file(server, filename="fingerprints.txt"):
723709
return json_dict[server]
724710
return ""
725711

712+
def create_https_connection(self, set_fingerprint, set_debug_level):
713+
context = ssl.create_default_context()
714+
context.check_hostname = False
715+
context.verify_mode = ssl.CERT_NONE
716+
# create https connection
717+
if self.proxy_host and self.proxy_port:
718+
conn = HTTPSConnection(self.proxy_host, self.proxy_port, context=context)
719+
conn.set_tunnel(self.server, self.get_port())
720+
else:
721+
conn = HTTPSConnection(self.server, self.get_port(), context=context)
722+
723+
# Set fingerprint
724+
if set_fingerprint:
725+
conn.fingerprint = self.fingerprint
726+
727+
# Set debug level
728+
if set_debug_level:
729+
conn.set_debuglevel(self.http_debug_level)
730+
conn.connect()
731+
return conn
732+
733+
def get_https_connection(self, set_fingerprint=True, set_debug_level=True):
734+
if self.single_conn:
735+
if self.conn is None:
736+
self.conn = self.create_https_connection(set_fingerprint, set_debug_level)
737+
return self.conn
738+
return self.create_https_connection(set_fingerprint, set_debug_level)
739+
740+
def close_connection(self):
741+
if self.conn:
742+
self.conn.close()
743+
726744

727745
class HTTPSConnection(http_client.HTTPSConnection):
728746
"""
729747
A class for making HTTPS connections that overrides the default HTTPS checks (e.g. not accepting
730748
self-signed-certificates) and replaces them with a server fingerprint check.
731749
"""
732-
733750
def connect(self):
734751
http_client.HTTPConnection.connect(self)
735752
self.sock = ssl.wrap_socket(self.sock, self.key_file, self.cert_file, cert_reqs=ssl.CERT_NONE)
736753

737754
def get_fingerprint_hash(self):
738-
try:
739-
http_client.HTTPConnection.connect(self)
740-
self.sock = ssl.wrap_socket(self.sock, self.key_file, self.cert_file, cert_reqs=ssl.CERT_NONE)
741-
except Exception:
742-
return ""
755+
if self.sock is None:
756+
self.connect()
743757
fingerprint = hashlib.new("SHA1", self.sock.getpeercert(True)).hexdigest()
744758
return fingerprint.upper()

0 commit comments

Comments
 (0)