diff --git a/FuelSDK/client.py b/FuelSDK/client.py index 1ebbfb8..6f42bc4 100644 --- a/FuelSDK/client.py +++ b/FuelSDK/client.py @@ -10,6 +10,8 @@ import suds.wsse from suds.sax.element import Element +from unverified_https_transport import UnverifiedHttpsTransport + from FuelSDK.objects import ET_DataExtension,ET_Subscriber @@ -40,6 +42,7 @@ class ET_Client(object): application_type = None authorization_code = None redirect_URI = None + ssl_verify = True ## get_server_wsdl - if True and a newer WSDL is on the server than the local filesystem retrieve it def __init__(self, get_server_wsdl = False, debug = False, params = None, tokenResponse=None): @@ -180,6 +183,13 @@ def configure_client(self, get_server_wsdl, params, tokenResponse): elif "FUELSDK_REDIRECT_URI" in os.environ: self.redirect_URI = os.environ["FUELSDK_REDIRECT_URI"] + if params is not None and "ssl_verify" in params: + self.ssl_verify = params["ssl_verify"] + elif config.has_option("Auth Service", "ssl_verify"): + self.ssl_verify = config.getboolean("Auth Service", "ssl_verify") + elif config.has_option("Web Services", "ssl_verify"): + self.ssl_verify = config.getboolean("Web Services", "ssl_verify") + if self.application_type in ["public", "web"]: if self.is_none_or_empty_or_blank(self.authorization_code) or self.is_none_or_empty_or_blank(self.redirect_URI): raise Exception('authorizationCode or redirectURI is null: For Public/Web Apps, the authorizationCode and redirectURI must be ' @@ -223,7 +233,7 @@ def load_wsdl(self, wsdl_url, wsdl_file_local_location, get_server_wsdl = False) if not os.path.exists(file_location) or os.path.getsize(file_location) == 0: #if there is no local copy or local copy is empty then go get it... self.retrieve_server_wsdl(wsdl_url, file_location) elif get_server_wsdl: - r = requests.head(wsdl_url) + r = requests.head(wsdl_url, verify=self.ssl_verify) if r is not None and 'last-modified' in r.headers: server_wsdl_updated = time.strptime(r.headers['last-modified'], '%a, %d %b %Y %H:%M:%S %Z') file_wsdl_updated = time.gmtime(os.path.getmtime(file_location)) @@ -237,7 +247,7 @@ def retrieve_server_wsdl(self, wsdl_url, file_location): """ get the WSDL from the server and save it locally """ - r = requests.get(wsdl_url) + r = requests.get(wsdl_url, verify=self.ssl_verify) f = open(file_location, 'w') f.write(r.text) @@ -246,7 +256,8 @@ def build_soap_client(self): if self.soap_endpoint is None or not self.soap_endpoint: self.soap_endpoint = self.get_soap_endpoint() - self.soap_client = suds.client.Client(self.wsdl_file_url, faults=False, cachingpolicy=1) + https_transport = None if self.ssl_verify else UnverifiedHttpsTransport() + self.soap_client = suds.client.Client(self.wsdl_file_url, faults=False, cachingpolicy=1, https_transport=https_transport) self.soap_client.set_options(location=self.soap_endpoint) self.soap_client.set_options(headers={'user-agent' : 'FuelSDK-Python-v1.3.0'}) @@ -290,7 +301,7 @@ def refresh_token(self, force_refresh = False): self.auth_url = self.auth_url.strip() self.auth_url = self.auth_url + legacyString - r = requests.post(self.auth_url, data=json.dumps(payload), headers=headers) + r = requests.post(self.auth_url, data=json.dumps(payload), headers=headers, verify=self.ssl_verify) tokenResponse = r.json() if 'accessToken' not in tokenResponse: @@ -319,7 +330,7 @@ def refresh_token_with_oAuth2(self, force_refresh=False): auth_endpoint = self.auth_url.strip() + '/v2/token' - r = requests.post(auth_endpoint, data=json.dumps(payload), headers=headers) + r = requests.post(auth_endpoint, data=json.dumps(payload), headers=headers, verify=self.ssl_verify) tokenResponse = r.json() if 'access_token' not in tokenResponse: @@ -393,7 +404,7 @@ def get_soap_endpoint(self): r = requests.get(self.base_api_url + '/platform/v1/endpoints/soap', headers={ 'user-agent': 'FuelSDK-Python-v1.3.0', 'authorization': 'Bearer ' + self.authToken - }) + }, verify=self.ssl_verify) contextResponse = r.json() if ('url' in contextResponse): diff --git a/FuelSDK/rest.py b/FuelSDK/rest.py index 698447b..a1e066b 100644 --- a/FuelSDK/rest.py +++ b/FuelSDK/rest.py @@ -323,7 +323,7 @@ def getMoreResults(self): ## ######## class ET_GetRest(ET_Constructor): - def __init__(self, auth_stub, endpoint, qs = None): + def __init__(self, auth_stub, endpoint, qs = None, ssl_verify = True): auth_stub.refresh_token() fullendpoint = endpoint urlSeparator = '?' @@ -332,7 +332,7 @@ def __init__(self, auth_stub, endpoint, qs = None): urlSeparator = '&' headers = {'authorization' : 'Bearer ' + auth_stub.authToken, 'user-agent' : 'FuelSDK-Python-v1.3.0'} - r = requests.get(fullendpoint, headers=headers) + r = requests.get(fullendpoint, headers=headers, verify=ssl_verify) self.more_results = False @@ -346,11 +346,11 @@ def __init__(self, auth_stub, endpoint, qs = None): ## ######## class ET_PostRest(ET_Constructor): - def __init__(self, auth_stub, endpoint, payload): + def __init__(self, auth_stub, endpoint, payload, ssl_verify = True): auth_stub.refresh_token() headers = {'content-type' : 'application/json', 'user-agent' : 'FuelSDK-Python-v1.3.0', 'authorization' : 'Bearer ' + auth_stub.authToken} - r = requests.post(endpoint, data=json.dumps(payload), headers=headers) + r = requests.post(endpoint, data=json.dumps(payload), headers=headers, verify=ssl_verify) obj = super(ET_PostRest, self).__init__(r, True) return obj @@ -361,11 +361,11 @@ def __init__(self, auth_stub, endpoint, payload): ## ######## class ET_PatchRest(ET_Constructor): - def __init__(self, auth_stub, endpoint, payload): + def __init__(self, auth_stub, endpoint, payload, ssl_verify = True): auth_stub.refresh_token() headers = {'content-type' : 'application/json', 'user-agent' : 'FuelSDK-Python-v1.3.0', 'authorization' : 'Bearer ' + auth_stub.authToken} - r = requests.patch(endpoint , data=json.dumps(payload), headers=headers) + r = requests.patch(endpoint , data=json.dumps(payload), headers=headers, verify=ssl_verify) obj = super(ET_PatchRest, self).__init__(r, True) return obj @@ -376,11 +376,11 @@ def __init__(self, auth_stub, endpoint, payload): ## ######## class ET_DeleteRest(ET_Constructor): - def __init__(self, auth_stub, endpoint): + def __init__(self, auth_stub, endpoint, ssl_verify = True): auth_stub.refresh_token() headers = {'authorization' : 'Bearer ' + auth_stub.authToken, 'user-agent' : 'FuelSDK-Python-v1.3.0'} - r = requests.delete(endpoint, headers=headers) + r = requests.delete(endpoint, headers=headers, verify=ssl_verify) obj = super(ET_DeleteRest, self).__init__(r, True) return obj diff --git a/FuelSDK/unverified_https_transport.py b/FuelSDK/unverified_https_transport.py new file mode 100644 index 0000000..e3009e9 --- /dev/null +++ b/FuelSDK/unverified_https_transport.py @@ -0,0 +1,19 @@ +import urllib.request +import ssl +import suds.transport.http + +class UnverifiedHttpsTransport(suds.transport.http.HttpTransport): + """ + Used with the suds client to bypass SSL certificate validation + """ + + def __init__(self, *args, **kwargs): + super(UnverifiedHttpsTransport, self).__init__(*args, **kwargs) + + def u2handlers(self): + handlers = super(UnverifiedHttpsTransport, self).u2handlers() + context = ssl.create_default_context() + context.check_hostname = False + context.verify_mode = ssl.CERT_NONE + handlers.append(urllib.request.HTTPSHandler(context=context)) + return handlers \ No newline at end of file diff --git a/README.md b/README.md index 1f3af5c..30f75b1 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ New Features in Version 1.3.0 baseapiurl: soapendpoint: wsdl_file_local_loc: /ExactTargetWSDL.xml + ssl_verify: [Auth Service] useOAuth2Authentication: True @@ -42,6 +43,7 @@ New Features in Version 1.3.0 applicationType: redirectURI: authorizationCode: + ssl_verify: ``` Example passing config as a parameter to ET_Client constructor: @@ -63,6 +65,7 @@ New Features in Version 1.3.0 'applicationType': '' 'redirectURI': '' 'authorizationCode': '' + 'ssl_verify': }) ``` @@ -86,11 +89,13 @@ New Features in Version 1.2.0 baseapiurl: soapendpoint: wsdl_file_local_loc: /ExactTargetWSDL.xml + ssl_verify: [Auth Service] useOAuth2Authentication: True accountId: scope: + ssl_verify: ``` Example passing config as a parameter to ET_Client constructor: @@ -108,7 +113,8 @@ New Features in Version 1.2.0 'wsdl_file_local_loc': r'/ExactTargetWSDL.xml', 'useOAuth2Authentication': 'True', 'accountId': '', - 'scope': '' + 'scope': '', + 'ssl_verify': 'False' }) ```