From b3d28f07f1ed6fe4f879ed78a9207272513ddbe7 Mon Sep 17 00:00:00 2001 From: geekerzp Date: Tue, 25 Aug 2015 17:58:14 +0800 Subject: [PATCH] Add option `verify_ssl` to switch SSL/TLS verification. --- .../src/main/resources/python/api.mustache | 2 +- .../main/resources/python/api_client.mustache | 51 +++--- .../resources/python/configuration.mustache | 6 + .../src/main/resources/python/rest.mustache | 149 +++++++----------- .../python/swagger_client/api_client.py | 51 +++--- .../python/swagger_client/apis/pet_api.py | 2 +- .../python/swagger_client/apis/store_api.py | 2 +- .../python/swagger_client/apis/user_api.py | 2 +- .../python/swagger_client/configuration.py | 6 + .../petstore/python/swagger_client/rest.py | 149 +++++++----------- 10 files changed, 180 insertions(+), 240 deletions(-) diff --git a/modules/swagger-codegen/src/main/resources/python/api.mustache b/modules/swagger-codegen/src/main/resources/python/api.mustache index f85d5962c97..b076fa5d3ea 100644 --- a/modules/swagger-codegen/src/main/resources/python/api.mustache +++ b/modules/swagger-codegen/src/main/resources/python/api.mustache @@ -43,7 +43,7 @@ class {{classname}}(object): self.api_client = api_client else: if not config.api_client: - config.api_client = ApiClient('{{basePath}}') + config.api_client = ApiClient() self.api_client = config.api_client {{#operation}} diff --git a/modules/swagger-codegen/src/main/resources/python/api_client.mustache b/modules/swagger-codegen/src/main/resources/python/api_client.mustache index 72b2f049854..1becd5547dd 100644 --- a/modules/swagger-codegen/src/main/resources/python/api_client.mustache +++ b/modules/swagger-codegen/src/main/resources/python/api_client.mustache @@ -20,7 +20,7 @@ Copyright 2015 SmartBear Software from __future__ import absolute_import from . import models -from .rest import RESTClient +from .rest import RESTClientObject from .rest import ApiException import os @@ -71,6 +71,7 @@ class ApiClient(object): """ Constructor of the class. """ + self.rest_client = RESTClientObject() self.default_headers = {} if header_name is not None: self.default_headers[header_name] = header_value @@ -330,35 +331,35 @@ class ApiClient(object): Makes the HTTP request using RESTClient. """ if method == "GET": - return RESTClient.GET(url, - query_params=query_params, - headers=headers) + return self.rest_client.GET(url, + query_params=query_params, + headers=headers) elif method == "HEAD": - return RESTClient.HEAD(url, - query_params=query_params, - headers=headers) + return self.rest_client.HEAD(url, + query_params=query_params, + headers=headers) elif method == "POST": - return RESTClient.POST(url, - query_params=query_params, - headers=headers, - post_params=post_params, - body=body) + return self.rest_client.POST(url, + query_params=query_params, + headers=headers, + post_params=post_params, + body=body) elif method == "PUT": - return RESTClient.PUT(url, - query_params=query_params, - headers=headers, - post_params=post_params, - body=body) + return self.rest_client.PUT(url, + query_params=query_params, + headers=headers, + post_params=post_params, + body=body) elif method == "PATCH": - return RESTClient.PATCH(url, - query_params=query_params, - headers=headers, - post_params=post_params, - body=body) + return self.rest_client.PATCH(url, + query_params=query_params, + headers=headers, + post_params=post_params, + body=body) elif method == "DELETE": - return RESTClient.DELETE(url, - query_params=query_params, - headers=headers) + return self.rest_client.DELETE(url, + query_params=query_params, + headers=headers) else: raise ValueError( "http method must be `GET`, `HEAD`," diff --git a/modules/swagger-codegen/src/main/resources/python/configuration.mustache b/modules/swagger-codegen/src/main/resources/python/configuration.mustache index b8ec002c44d..07625c67e48 100644 --- a/modules/swagger-codegen/src/main/resources/python/configuration.mustache +++ b/modules/swagger-codegen/src/main/resources/python/configuration.mustache @@ -79,6 +79,12 @@ class Configuration(object): self.__debug = False self.init_logger() + # SSL/TLS verification + # Set this to false to skip verifying SSL certificate when calling API from https server. + self.verify_ssl = True + # Set this to customize the certificate file to verify the peer. + self.ssl_ca_cert = None + def init_logger(self): """ Initializes logger settings. diff --git a/modules/swagger-codegen/src/main/resources/python/rest.mustache b/modules/swagger-codegen/src/main/resources/python/rest.mustache index f9f85f294dc..1481cbff3d5 100644 --- a/modules/swagger-codegen/src/main/resources/python/rest.mustache +++ b/modules/swagger-codegen/src/main/resources/python/rest.mustache @@ -18,6 +18,7 @@ Copyright 2015 SmartBear Software Credit: this file (rest.py) is modified based on rest.py in Dropbox Python SDK: https://www.dropbox.com/developers/core/sdks/python """ +from __future__ import absolute_import import sys import io @@ -29,6 +30,8 @@ import logging # python 2 and python 3 compatibility library from six import iteritems +from .configuration import Configuration + try: import urllib3 except ImportError: @@ -69,31 +72,24 @@ class RESTResponse(io.IOBase): class RESTClientObject(object): def __init__(self, pools_size=4): - # http pool manager - self.pool_manager = urllib3.PoolManager( - num_pools=pools_size - ) + if Configuration().verify_ssl: + cert_reqs = ssl.CERT_REQUIRED + else: + cert_reqs = ssl.CERT_NONE + + if Configuration().ssl_ca_cert: + ca_certs = Configuration().ssl_ca_cert + else: + # if not set certificate file, use Mozilla's root certificates. + ca_certs = certifi.where() # https pool manager - # certificates validated using Mozilla’s root certificates - self.ssl_pool_manager = urllib3.PoolManager( + self.pool_manager = urllib3.PoolManager( num_pools=pools_size, - cert_reqs=ssl.CERT_REQUIRED, - ca_certs=certifi.where() + cert_reqs=cert_reqs, + ca_certs=ca_certs ) - def agent(self, url): - """ - Use `urllib3.util.parse_url` for backward compatibility. - Return proper pool manager for the http/https schemes. - """ - url = urllib3.util.parse_url(url) - scheme = url.scheme - if scheme == 'https': - return self.ssl_pool_manager - else: - return self.pool_manager - def request(self, method, url, query_params=None, headers=None, body=None, post_params=None): """ @@ -120,32 +116,37 @@ class RESTClientObject(object): if 'Content-Type' not in headers: headers['Content-Type'] = 'application/json' - # For `POST`, `PUT`, `PATCH` - if method in ['POST', 'PUT', 'PATCH']: - if query_params: - url += '?' + urlencode(query_params) - if headers['Content-Type'] == 'application/json': - r = self.agent(url).request(method, url, - body=json.dumps(body), - headers=headers) - if headers['Content-Type'] == 'application/x-www-form-urlencoded': - r = self.agent(url).request(method, url, - fields=post_params, - encode_multipart=False, - headers=headers) - if headers['Content-Type'] == 'multipart/form-data': - # must del headers['Content-Type'], or the correct Content-Type - # which generated by urllib3 will be overwritten. - del headers['Content-Type'] - r = self.agent(url).request(method, url, - fields=post_params, - encode_multipart=True, - headers=headers) - # For `GET`, `HEAD`, `DELETE` - else: - r = self.agent(url).request(method, url, - fields=query_params, - headers=headers) + try: + # For `POST`, `PUT`, `PATCH` + if method in ['POST', 'PUT', 'PATCH']: + if query_params: + url += '?' + urlencode(query_params) + if headers['Content-Type'] == 'application/json': + r = self.pool_manager.request(method, url, + body=json.dumps(body), + headers=headers) + if headers['Content-Type'] == 'application/x-www-form-urlencoded': + r = self.pool_manager.request(method, url, + fields=post_params, + encode_multipart=False, + headers=headers) + if headers['Content-Type'] == 'multipart/form-data': + # must del headers['Content-Type'], or the correct Content-Type + # which generated by urllib3 will be overwritten. + del headers['Content-Type'] + r = self.pool_manager.request(method, url, + fields=post_params, + encode_multipart=True, + headers=headers) + # For `GET`, `HEAD`, `DELETE` + else: + r = self.pool_manager.request(method, url, + fields=query_params, + headers=headers) + except urllib3.exceptions.SSLError as e: + msg = "{0}\n{1}".format(type(e).__name__, str(e)) + raise ApiException(status=0, reason=msg) + r = RESTResponse(r) # In the python 3, the response.data is bytes. @@ -227,58 +228,20 @@ class ApiException(Exception): return error_message -class RESTClient(object): - """ - A class with all class methods to perform JSON requests. - """ - IMPL = RESTClientObject() - @classmethod - def request(cls, *n, **kw): - """ - Perform a REST request and parse the response. - """ - return cls.IMPL.request(*n, **kw) - @classmethod - def GET(cls, *n, **kw): - """ - Perform a GET request using `RESTClient.request()`. - """ - return cls.IMPL.GET(*n, **kw) - @classmethod - def HEAD(cls, *n, **kw): - """ - Perform a HEAD request using `RESTClient.request()`. - """ - return cls.IMPL.GET(*n, **kw) - @classmethod - def POST(cls, *n, **kw): - """ - Perform a POST request using `RESTClient.request()` - """ - return cls.IMPL.POST(*n, **kw) - @classmethod - def PUT(cls, *n, **kw): - """ - Perform a PUT request using `RESTClient.request()` - """ - return cls.IMPL.PUT(*n, **kw) - @classmethod - def PATCH(cls, *n, **kw): - """ - Perform a PATCH request using `RESTClient.request()` - """ - return cls.IMPL.PATCH(*n, **kw) - @classmethod - def DELETE(cls, *n, **kw): - """ - Perform a DELETE request using `RESTClient.request()` - """ - return cls.IMPL.DELETE(*n, **kw) + + + + + + + + + diff --git a/samples/client/petstore/python/swagger_client/api_client.py b/samples/client/petstore/python/swagger_client/api_client.py index 33e8acb8ba1..1030bf9a838 100644 --- a/samples/client/petstore/python/swagger_client/api_client.py +++ b/samples/client/petstore/python/swagger_client/api_client.py @@ -20,7 +20,7 @@ Copyright 2015 SmartBear Software from __future__ import absolute_import from . import models -from .rest import RESTClient +from .rest import RESTClientObject from .rest import ApiException import os @@ -71,6 +71,7 @@ class ApiClient(object): """ Constructor of the class. """ + self.rest_client = RESTClientObject() self.default_headers = {} if header_name is not None: self.default_headers[header_name] = header_value @@ -330,35 +331,35 @@ class ApiClient(object): Makes the HTTP request using RESTClient. """ if method == "GET": - return RESTClient.GET(url, - query_params=query_params, - headers=headers) + return self.rest_client.GET(url, + query_params=query_params, + headers=headers) elif method == "HEAD": - return RESTClient.HEAD(url, - query_params=query_params, - headers=headers) + return self.rest_client.HEAD(url, + query_params=query_params, + headers=headers) elif method == "POST": - return RESTClient.POST(url, - query_params=query_params, - headers=headers, - post_params=post_params, - body=body) + return self.rest_client.POST(url, + query_params=query_params, + headers=headers, + post_params=post_params, + body=body) elif method == "PUT": - return RESTClient.PUT(url, - query_params=query_params, - headers=headers, - post_params=post_params, - body=body) + return self.rest_client.PUT(url, + query_params=query_params, + headers=headers, + post_params=post_params, + body=body) elif method == "PATCH": - return RESTClient.PATCH(url, - query_params=query_params, - headers=headers, - post_params=post_params, - body=body) + return self.rest_client.PATCH(url, + query_params=query_params, + headers=headers, + post_params=post_params, + body=body) elif method == "DELETE": - return RESTClient.DELETE(url, - query_params=query_params, - headers=headers) + return self.rest_client.DELETE(url, + query_params=query_params, + headers=headers) else: raise ValueError( "http method must be `GET`, `HEAD`," diff --git a/samples/client/petstore/python/swagger_client/apis/pet_api.py b/samples/client/petstore/python/swagger_client/apis/pet_api.py index 0dcdbc9ddae..b162cc534c3 100644 --- a/samples/client/petstore/python/swagger_client/apis/pet_api.py +++ b/samples/client/petstore/python/swagger_client/apis/pet_api.py @@ -42,7 +42,7 @@ class PetApi(object): self.api_client = api_client else: if not config.api_client: - config.api_client = ApiClient('http://petstore.swagger.io/v2') + config.api_client = ApiClient() self.api_client = config.api_client def update_pet(self, **kwargs): diff --git a/samples/client/petstore/python/swagger_client/apis/store_api.py b/samples/client/petstore/python/swagger_client/apis/store_api.py index affb76f6c8b..9e08a0b2f47 100644 --- a/samples/client/petstore/python/swagger_client/apis/store_api.py +++ b/samples/client/petstore/python/swagger_client/apis/store_api.py @@ -42,7 +42,7 @@ class StoreApi(object): self.api_client = api_client else: if not config.api_client: - config.api_client = ApiClient('http://petstore.swagger.io/v2') + config.api_client = ApiClient() self.api_client = config.api_client def get_inventory(self, **kwargs): diff --git a/samples/client/petstore/python/swagger_client/apis/user_api.py b/samples/client/petstore/python/swagger_client/apis/user_api.py index 574379491ec..1c96e1e923e 100644 --- a/samples/client/petstore/python/swagger_client/apis/user_api.py +++ b/samples/client/petstore/python/swagger_client/apis/user_api.py @@ -42,7 +42,7 @@ class UserApi(object): self.api_client = api_client else: if not config.api_client: - config.api_client = ApiClient('http://petstore.swagger.io/v2') + config.api_client = ApiClient() self.api_client = config.api_client def create_user(self, **kwargs): diff --git a/samples/client/petstore/python/swagger_client/configuration.py b/samples/client/petstore/python/swagger_client/configuration.py index b253f561abe..4ca9342c057 100644 --- a/samples/client/petstore/python/swagger_client/configuration.py +++ b/samples/client/petstore/python/swagger_client/configuration.py @@ -79,6 +79,12 @@ class Configuration(object): self.__debug = False self.init_logger() + # SSL/TLS verification + # Set this to false to skip verifying SSL certificate when calling API from https server. + self.verify_ssl = True + # Set this to customize the certificate file to verify the peer. + self.ssl_ca_cert = None + def init_logger(self): """ Initializes logger settings. diff --git a/samples/client/petstore/python/swagger_client/rest.py b/samples/client/petstore/python/swagger_client/rest.py index f9f85f294dc..1481cbff3d5 100644 --- a/samples/client/petstore/python/swagger_client/rest.py +++ b/samples/client/petstore/python/swagger_client/rest.py @@ -18,6 +18,7 @@ Copyright 2015 SmartBear Software Credit: this file (rest.py) is modified based on rest.py in Dropbox Python SDK: https://www.dropbox.com/developers/core/sdks/python """ +from __future__ import absolute_import import sys import io @@ -29,6 +30,8 @@ import logging # python 2 and python 3 compatibility library from six import iteritems +from .configuration import Configuration + try: import urllib3 except ImportError: @@ -69,31 +72,24 @@ class RESTResponse(io.IOBase): class RESTClientObject(object): def __init__(self, pools_size=4): - # http pool manager - self.pool_manager = urllib3.PoolManager( - num_pools=pools_size - ) + if Configuration().verify_ssl: + cert_reqs = ssl.CERT_REQUIRED + else: + cert_reqs = ssl.CERT_NONE + + if Configuration().ssl_ca_cert: + ca_certs = Configuration().ssl_ca_cert + else: + # if not set certificate file, use Mozilla's root certificates. + ca_certs = certifi.where() # https pool manager - # certificates validated using Mozilla’s root certificates - self.ssl_pool_manager = urllib3.PoolManager( + self.pool_manager = urllib3.PoolManager( num_pools=pools_size, - cert_reqs=ssl.CERT_REQUIRED, - ca_certs=certifi.where() + cert_reqs=cert_reqs, + ca_certs=ca_certs ) - def agent(self, url): - """ - Use `urllib3.util.parse_url` for backward compatibility. - Return proper pool manager for the http/https schemes. - """ - url = urllib3.util.parse_url(url) - scheme = url.scheme - if scheme == 'https': - return self.ssl_pool_manager - else: - return self.pool_manager - def request(self, method, url, query_params=None, headers=None, body=None, post_params=None): """ @@ -120,32 +116,37 @@ class RESTClientObject(object): if 'Content-Type' not in headers: headers['Content-Type'] = 'application/json' - # For `POST`, `PUT`, `PATCH` - if method in ['POST', 'PUT', 'PATCH']: - if query_params: - url += '?' + urlencode(query_params) - if headers['Content-Type'] == 'application/json': - r = self.agent(url).request(method, url, - body=json.dumps(body), - headers=headers) - if headers['Content-Type'] == 'application/x-www-form-urlencoded': - r = self.agent(url).request(method, url, - fields=post_params, - encode_multipart=False, - headers=headers) - if headers['Content-Type'] == 'multipart/form-data': - # must del headers['Content-Type'], or the correct Content-Type - # which generated by urllib3 will be overwritten. - del headers['Content-Type'] - r = self.agent(url).request(method, url, - fields=post_params, - encode_multipart=True, - headers=headers) - # For `GET`, `HEAD`, `DELETE` - else: - r = self.agent(url).request(method, url, - fields=query_params, - headers=headers) + try: + # For `POST`, `PUT`, `PATCH` + if method in ['POST', 'PUT', 'PATCH']: + if query_params: + url += '?' + urlencode(query_params) + if headers['Content-Type'] == 'application/json': + r = self.pool_manager.request(method, url, + body=json.dumps(body), + headers=headers) + if headers['Content-Type'] == 'application/x-www-form-urlencoded': + r = self.pool_manager.request(method, url, + fields=post_params, + encode_multipart=False, + headers=headers) + if headers['Content-Type'] == 'multipart/form-data': + # must del headers['Content-Type'], or the correct Content-Type + # which generated by urllib3 will be overwritten. + del headers['Content-Type'] + r = self.pool_manager.request(method, url, + fields=post_params, + encode_multipart=True, + headers=headers) + # For `GET`, `HEAD`, `DELETE` + else: + r = self.pool_manager.request(method, url, + fields=query_params, + headers=headers) + except urllib3.exceptions.SSLError as e: + msg = "{0}\n{1}".format(type(e).__name__, str(e)) + raise ApiException(status=0, reason=msg) + r = RESTResponse(r) # In the python 3, the response.data is bytes. @@ -227,58 +228,20 @@ class ApiException(Exception): return error_message -class RESTClient(object): - """ - A class with all class methods to perform JSON requests. - """ - IMPL = RESTClientObject() - @classmethod - def request(cls, *n, **kw): - """ - Perform a REST request and parse the response. - """ - return cls.IMPL.request(*n, **kw) - @classmethod - def GET(cls, *n, **kw): - """ - Perform a GET request using `RESTClient.request()`. - """ - return cls.IMPL.GET(*n, **kw) - @classmethod - def HEAD(cls, *n, **kw): - """ - Perform a HEAD request using `RESTClient.request()`. - """ - return cls.IMPL.GET(*n, **kw) - @classmethod - def POST(cls, *n, **kw): - """ - Perform a POST request using `RESTClient.request()` - """ - return cls.IMPL.POST(*n, **kw) - @classmethod - def PUT(cls, *n, **kw): - """ - Perform a PUT request using `RESTClient.request()` - """ - return cls.IMPL.PUT(*n, **kw) - @classmethod - def PATCH(cls, *n, **kw): - """ - Perform a PATCH request using `RESTClient.request()` - """ - return cls.IMPL.PATCH(*n, **kw) - @classmethod - def DELETE(cls, *n, **kw): - """ - Perform a DELETE request using `RESTClient.request()` - """ - return cls.IMPL.DELETE(*n, **kw) + + + + + + + + +