From ee8e946640a077c3b9c863a3692743d35d627fc3 Mon Sep 17 00:00:00 2001 From: Elena Darevsky Date: Tue, 10 Dec 2024 17:35:25 +0200 Subject: [PATCH 1/3] Add option to disable host check when sending requests --- GSSDK.py | 55 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/GSSDK.py b/GSSDK.py index 31fdcd9..96b1955 100644 --- a/GSSDK.py +++ b/GSSDK.py @@ -17,7 +17,7 @@ from urllib.request import ProxyHandler from urllib.request import install_opener from urllib.request import urlopen - from http.client import HTTPConnection + from http.client import HTTPSConnection from http.client import HTTPS_PORT from urllib.request import HTTPSHandler from urllib.parse import quote_plus @@ -29,7 +29,7 @@ from urllib2 import ProxyHandler from urllib2 import install_opener from urllib2 import urlopen - from httplib import HTTPConnection + from httplib import HTTPSConnection from httplib import HTTPS_PORT from urllib2 import HTTPSHandler from urllib import quote_plus @@ -41,7 +41,7 @@ import socket import os import ssl -import copy +import copy from hashlib import sha1 from base64 import b64decode, b64encode @@ -85,7 +85,7 @@ class GSRequest(): _useHTTPS = False _apiDomain = DEFAULT_API_DOMAIN - def __init__(self, apiKey=None, secretKey=None, apiMethod=None, params=None, useHTTPS=False, userKey=None): + def __init__(self, apiKey=None, secretKey=None, apiMethod=None, params=None, useHTTPS=False, userKey=None, enable_host_check=True): """ Constructs a request using the apiKey and secretKey. @param apiKey @@ -118,6 +118,7 @@ def __init__(self, apiKey=None, secretKey=None, apiMethod=None, params=None, use self._secretKey = secretKey self._userKey = userKey self._traceLog = list() + self._enableHostCheck = enable_host_check self.traceField("apiMethod", apiMethod) self.traceField("apiKey", apiKey) @@ -188,7 +189,7 @@ def send(self, timeout=None): return GSResponse(self._method, None, self._params, errCode, errMsg, self._traceLog) - def sendRequest(self, httpMethod, domain, path, params, token, secret=None, useHTTPS=False, timeout=None, userKey=None): + def sendRequest(self, httpMethod, domain, path, params, token, secret=None, useHTTPS=False, timeout=None, userKey=None, enable_host_check=True): params["sdk"] = "python_" + self.VERSION # prepare query params @@ -216,16 +217,15 @@ def sendRequest(self, httpMethod, domain, path, params, token, secret=None, useH params["oauth_token"] = token # get rest response. - res = self.curl(resourceURI, params, timeout) + res = self.curl(resourceURI, params, timeout, enable_host_check) return res - def curl(self, url, params=None, timeout=None): + def curl(self, url, params=None, timeout=None, enable_host_check=True): queryString = self.buildQS(params) - self.traceField("URL", url) self.traceField("postData", queryString) @@ -234,12 +234,12 @@ def curl(self, url, params=None, timeout=None): if self._proxy: opener = build_opener( HTTPHandler(), - ValidHTTPSHandler(), + ValidHTTPSHandler(enable_host_check), ProxyHandler({proto: self._proxy})) else: opener = build_opener( HTTPHandler(), - ValidHTTPSHandler()) + ValidHTTPSHandler(enable_host_check)) queryString = queryString.encode('utf-8') @@ -440,11 +440,12 @@ def __str__(self): return sb -class ValidHTTPSConnection(HTTPConnection): +class ValidHTTPSConnection(HTTPSConnection): default_port = HTTPS_PORT def __init__(self, *args, **kwargs): - HTTPConnection.__init__(self, *args, **kwargs) + HTTPSConnection.__init__(self, *args, **kwargs) + self._context = kwargs.get('context') def connect(self): sock = socket.create_connection((self.host, self.port), self.timeout, self.source_address) @@ -453,18 +454,28 @@ def connect(self): self.sock = sock self._tunnel() - context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) - context.minumum_version = ssl.TLSVersion.TLSv1_2 - context.load_verify_locations(GSRequest.caCertsPath) - context.verify_mode = ssl.CERT_REQUIRED - context.check_hostname = True - - self.sock = context.wrap_socket(sock, server_hostname=self.host) + self.sock = self._context.wrap_socket(sock, server_hostname=self.host) class ValidHTTPSHandler(HTTPSHandler): + def __init__(self, enable_host_check=True): + super().__init__() + self._enableHostCheck = enable_host_check + def https_open(self, req): - return self.do_open(ValidHTTPSConnection, req) + return self.do_open(self.get_connection, req) + + def get_connection(self, host, timeout): + return ValidHTTPSConnection(host, timeout = timeout, context = self.create_context()) + + def create_context(self): + context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + context.minimum_version = ssl.TLSVersion.TLSv1_2 + context.load_verify_locations(GSRequest.caCertsPath) + context.verify_mode = ssl.CERT_REQUIRED + context.check_hostname = self._enableHostCheck + + return context class SigUtils(): @@ -483,7 +494,7 @@ def validateUserSignature(UID, timestamp, secret, signature, expiration=None): def validateUserSignatureWithExpiration(UID, timestamp, secret, signature, expiration): expired = SigUtils.signatureTimestampExpired(timestamp, expiration) signatureValidated = SigUtils.validateUserSignature(UID, timestamp, secret, signature) - return not expired and signatureValidated + return not expired and signatureValidated @staticmethod def validateFriendSignature(UID, timestamp, friendUID, secret, signature, expiration=None): @@ -493,7 +504,7 @@ def validateFriendSignature(UID, timestamp, friendUID, secret, signature, expira return expectedSig == signature else: expired = SigUtils.signatureTimestampExpired(timestamp, expiration) - return not expired and expectedSig == signature + return not expired and expectedSig == signature @staticmethod def validateFriendSignatureWithExpiration(UID, timestamp, friendUID, secret, signature, expiration): From 17b8e27e87f7e029e673453e8a80c66f86063915 Mon Sep 17 00:00:00 2001 From: Elena Darevsky Date: Tue, 10 Dec 2024 17:37:08 +0200 Subject: [PATCH 2/3] Bump version --- GSSDK.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GSSDK.py b/GSSDK.py index 96b1955..ddb0d1c 100644 --- a/GSSDK.py +++ b/GSSDK.py @@ -68,7 +68,7 @@ def __str__(self): class GSRequest(): DEFAULT_API_DOMAIN = "us1.gigya.com" - VERSION = "3.5.0" + VERSION = "3.5.1" caCertsPath = os.path.join(os.path.dirname(__file__), "cacert.pem") _domain = "" From 70132dec8c59365787c307869607eae9c6627fb8 Mon Sep 17 00:00:00 2001 From: Elena Darevsky Date: Wed, 11 Dec 2024 14:24:01 +0200 Subject: [PATCH 3/3] Update GSRequest params description --- GSSDK.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GSSDK.py b/GSSDK.py index ddb0d1c..cb80ee2 100644 --- a/GSSDK.py +++ b/GSSDK.py @@ -95,6 +95,7 @@ def __init__(self, apiKey=None, secretKey=None, apiMethod=None, params=None, use @param params the request parameters @param useHTTPS useHTTPS set this to true if you want to use HTTPS. @param userKey A key of an admin user with extra permissions. + @param enable_host_check Hostcheck can be disabled by passing enable_host_check=false when using HTTPS. Can be necessary when using proxy. Default is True If this parameter is provided, then the secretKey parameter is assumed to be the admin user's secret key and not the site's secret key. """ @@ -234,7 +235,7 @@ def curl(self, url, params=None, timeout=None, enable_host_check=True): if self._proxy: opener = build_opener( HTTPHandler(), - ValidHTTPSHandler(enable_host_check), + ValidHTTPSHandler(enable_host_check), # maybe always send False??? ProxyHandler({proto: self._proxy})) else: opener = build_opener(