From a0b984737024d710a9a994bd214cd6445acca0d5 Mon Sep 17 00:00:00 2001 From: Michael Farrell Date: Thu, 20 Feb 2025 17:26:39 +1000 Subject: [PATCH 1/2] Add `ca_cert_data` parameter to Python client. This lets a client validate a server's CA certificate chain using a variable/constant containing PEM (`str`) or DER (`bytes`) data, rather than needing to reference a file on disk. --- .../src/main/resources/python/asyncio/rest.mustache | 3 ++- .../src/main/resources/python/configuration.mustache | 7 +++++++ .../src/main/resources/python/rest.mustache | 1 + .../openapi_client/configuration.py | 7 +++++++ .../openapi_client/rest.py | 1 + .../client/echo_api/python/openapi_client/configuration.py | 7 +++++++ samples/client/echo_api/python/openapi_client/rest.py | 1 + .../petstore/python-aiohttp/petstore_api/configuration.py | 7 +++++++ .../client/petstore/python-aiohttp/petstore_api/rest.py | 3 ++- .../client/petstore/python/petstore_api/configuration.py | 7 +++++++ .../openapi3/client/petstore/python/petstore_api/rest.py | 1 + 11 files changed, 43 insertions(+), 2 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/python/asyncio/rest.mustache b/modules/openapi-generator/src/main/resources/python/asyncio/rest.mustache index 3b201d99ba9b..937e76ed5a4c 100644 --- a/modules/openapi-generator/src/main/resources/python/asyncio/rest.mustache +++ b/modules/openapi-generator/src/main/resources/python/asyncio/rest.mustache @@ -47,7 +47,8 @@ class RESTClientObject: self.maxsize = configuration.connection_pool_maxsize self.ssl_context = ssl.create_default_context( - cafile=configuration.ssl_ca_cert + cafile=configuration.ssl_ca_cert, + cadata=configuration.ca_cert_data, ) if configuration.cert_file: self.ssl_context.load_cert_chain( diff --git a/modules/openapi-generator/src/main/resources/python/configuration.mustache b/modules/openapi-generator/src/main/resources/python/configuration.mustache index 667a5c88fc93..de8ab2cae070 100644 --- a/modules/openapi-generator/src/main/resources/python/configuration.mustache +++ b/modules/openapi-generator/src/main/resources/python/configuration.mustache @@ -183,6 +183,8 @@ class Configuration: :param ssl_ca_cert: str - the path to a file of concatenated CA certificates in PEM format. :param retries: Number of retries for API requests. + :param ca_cert_data: str|bytes - verify the peer using concatenated CA + certificate data in PEM (str) or DER (bytes) format. {{#hasAuthMethods}} :Example: @@ -289,6 +291,7 @@ conf = {{{packageName}}}.Configuration( ignore_operation_servers: bool=False, ssl_ca_cert: Optional[str]=None, retries: Optional[int] = None, + ca_cert_data: Optional[str | bytes] = None, *, debug: Optional[bool] = None, ) -> None: @@ -373,6 +376,10 @@ conf = {{{packageName}}}.Configuration( self.ssl_ca_cert = ssl_ca_cert """Set this to customize the certificate file to verify the peer. """ + self.ca_cert_data = ca_cert_data + """Set this to verify the peer using PEM (str) or DER (bytes) + certificate data. + """ self.cert_file = None """client certificate file """ diff --git a/modules/openapi-generator/src/main/resources/python/rest.mustache b/modules/openapi-generator/src/main/resources/python/rest.mustache index fc71a59cf404..f545066bb677 100644 --- a/modules/openapi-generator/src/main/resources/python/rest.mustache +++ b/modules/openapi-generator/src/main/resources/python/rest.mustache @@ -66,6 +66,7 @@ class RESTClientObject: "ca_certs": configuration.ssl_ca_cert, "cert_file": configuration.cert_file, "key_file": configuration.key_file, + "ca_cert_data": configuration.ca_cert_data, } if configuration.assert_hostname is not None: pool_args['assert_hostname'] = ( diff --git a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py index e48902fd8ede..ce10b7eb4af6 100644 --- a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py +++ b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py @@ -163,6 +163,8 @@ class Configuration: :param ssl_ca_cert: str - the path to a file of concatenated CA certificates in PEM format. :param retries: Number of retries for API requests. + :param ca_cert_data: str|bytes - verify the peer using concatenated CA + certificate data in PEM (str) or DER (bytes) format. :Example: @@ -200,6 +202,7 @@ def __init__( ignore_operation_servers: bool=False, ssl_ca_cert: Optional[str]=None, retries: Optional[int] = None, + ca_cert_data: Optional[str | bytes] = None, *, debug: Optional[bool] = None, ) -> None: @@ -277,6 +280,10 @@ def __init__( self.ssl_ca_cert = ssl_ca_cert """Set this to customize the certificate file to verify the peer. """ + self.ca_cert_data = ca_cert_data + """Set this to verify the peer using PEM (str) or DER (bytes) + certificate data. + """ self.cert_file = None """client certificate file """ diff --git a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/rest.py b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/rest.py index 91fb8eb029dc..89600d574a46 100644 --- a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/rest.py +++ b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/rest.py @@ -77,6 +77,7 @@ def __init__(self, configuration) -> None: "ca_certs": configuration.ssl_ca_cert, "cert_file": configuration.cert_file, "key_file": configuration.key_file, + "ca_cert_data": configuration.ca_cert_data, } if configuration.assert_hostname is not None: pool_args['assert_hostname'] = ( diff --git a/samples/client/echo_api/python/openapi_client/configuration.py b/samples/client/echo_api/python/openapi_client/configuration.py index e48902fd8ede..ce10b7eb4af6 100644 --- a/samples/client/echo_api/python/openapi_client/configuration.py +++ b/samples/client/echo_api/python/openapi_client/configuration.py @@ -163,6 +163,8 @@ class Configuration: :param ssl_ca_cert: str - the path to a file of concatenated CA certificates in PEM format. :param retries: Number of retries for API requests. + :param ca_cert_data: str|bytes - verify the peer using concatenated CA + certificate data in PEM (str) or DER (bytes) format. :Example: @@ -200,6 +202,7 @@ def __init__( ignore_operation_servers: bool=False, ssl_ca_cert: Optional[str]=None, retries: Optional[int] = None, + ca_cert_data: Optional[str | bytes] = None, *, debug: Optional[bool] = None, ) -> None: @@ -277,6 +280,10 @@ def __init__( self.ssl_ca_cert = ssl_ca_cert """Set this to customize the certificate file to verify the peer. """ + self.ca_cert_data = ca_cert_data + """Set this to verify the peer using PEM (str) or DER (bytes) + certificate data. + """ self.cert_file = None """client certificate file """ diff --git a/samples/client/echo_api/python/openapi_client/rest.py b/samples/client/echo_api/python/openapi_client/rest.py index b97741ddfce4..d2bd065dc08f 100644 --- a/samples/client/echo_api/python/openapi_client/rest.py +++ b/samples/client/echo_api/python/openapi_client/rest.py @@ -77,6 +77,7 @@ def __init__(self, configuration) -> None: "ca_certs": configuration.ssl_ca_cert, "cert_file": configuration.cert_file, "key_file": configuration.key_file, + "ca_cert_data": configuration.ca_cert_data, } if configuration.assert_hostname is not None: pool_args['assert_hostname'] = ( diff --git a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/configuration.py index 0282a0aa460b..3ddcd1cafd8d 100644 --- a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/configuration.py @@ -168,6 +168,8 @@ class Configuration: :param ssl_ca_cert: str - the path to a file of concatenated CA certificates in PEM format. :param retries: Number of retries for API requests. + :param ca_cert_data: str|bytes - verify the peer using concatenated CA + certificate data in PEM (str) or DER (bytes) format. :Example: @@ -264,6 +266,7 @@ def __init__( ignore_operation_servers: bool=False, ssl_ca_cert: Optional[str]=None, retries: Optional[int] = None, + ca_cert_data: Optional[str | bytes] = None, *, debug: Optional[bool] = None, ) -> None: @@ -346,6 +349,10 @@ def __init__( self.ssl_ca_cert = ssl_ca_cert """Set this to customize the certificate file to verify the peer. """ + self.ca_cert_data = ca_cert_data + """Set this to verify the peer using PEM (str) or DER (bytes) + certificate data. + """ self.cert_file = None """client certificate file """ diff --git a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/rest.py b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/rest.py index ec1da5adf9e3..5ee6cd4b2df8 100644 --- a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/rest.py +++ b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/rest.py @@ -57,7 +57,8 @@ def __init__(self, configuration) -> None: self.maxsize = configuration.connection_pool_maxsize self.ssl_context = ssl.create_default_context( - cafile=configuration.ssl_ca_cert + cafile=configuration.ssl_ca_cert, + cadata=configuration.ca_cert_data, ) if configuration.cert_file: self.ssl_context.load_cert_chain( diff --git a/samples/openapi3/client/petstore/python/petstore_api/configuration.py b/samples/openapi3/client/petstore/python/petstore_api/configuration.py index f374b0bc53d4..a78b6698ea91 100755 --- a/samples/openapi3/client/petstore/python/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python/petstore_api/configuration.py @@ -169,6 +169,8 @@ class Configuration: :param ssl_ca_cert: str - the path to a file of concatenated CA certificates in PEM format. :param retries: Number of retries for API requests. + :param ca_cert_data: str|bytes - verify the peer using concatenated CA + certificate data in PEM (str) or DER (bytes) format. :Example: @@ -265,6 +267,7 @@ def __init__( ignore_operation_servers: bool=False, ssl_ca_cert: Optional[str]=None, retries: Optional[int] = None, + ca_cert_data: Optional[str | bytes] = None, *, debug: Optional[bool] = None, ) -> None: @@ -347,6 +350,10 @@ def __init__( self.ssl_ca_cert = ssl_ca_cert """Set this to customize the certificate file to verify the peer. """ + self.ca_cert_data = ca_cert_data + """Set this to verify the peer using PEM (str) or DER (bytes) + certificate data. + """ self.cert_file = None """client certificate file """ diff --git a/samples/openapi3/client/petstore/python/petstore_api/rest.py b/samples/openapi3/client/petstore/python/petstore_api/rest.py index 3c7cc883f69b..abc7aa289384 100755 --- a/samples/openapi3/client/petstore/python/petstore_api/rest.py +++ b/samples/openapi3/client/petstore/python/petstore_api/rest.py @@ -76,6 +76,7 @@ def __init__(self, configuration) -> None: "ca_certs": configuration.ssl_ca_cert, "cert_file": configuration.cert_file, "key_file": configuration.key_file, + "ca_cert_data": configuration.ca_cert_data, } if configuration.assert_hostname is not None: pool_args['assert_hostname'] = ( From e614f9691343c0e3afd2aa1d783526e5fcc25604 Mon Sep 17 00:00:00 2001 From: Michael Farrell Date: Fri, 21 Feb 2025 15:11:16 +1000 Subject: [PATCH 2/2] python: Fix `ca_cert_data` on Python 3.8 --- .../src/main/resources/python/configuration.mustache | 10 +++++----- .../openapi_client/configuration.py | 10 +++++----- .../echo_api/python/openapi_client/configuration.py | 10 +++++----- .../python-aiohttp/petstore_api/configuration.py | 10 +++++----- .../petstore/python/petstore_api/configuration.py | 10 +++++----- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/python/configuration.mustache b/modules/openapi-generator/src/main/resources/python/configuration.mustache index de8ab2cae070..0dca8be3583a 100644 --- a/modules/openapi-generator/src/main/resources/python/configuration.mustache +++ b/modules/openapi-generator/src/main/resources/python/configuration.mustache @@ -10,7 +10,7 @@ from logging import FileHandler import multiprocessing {{/asyncio}} import sys -from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict +from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union from typing_extensions import NotRequired, Self import urllib3 @@ -183,8 +183,8 @@ class Configuration: :param ssl_ca_cert: str - the path to a file of concatenated CA certificates in PEM format. :param retries: Number of retries for API requests. - :param ca_cert_data: str|bytes - verify the peer using concatenated CA - certificate data in PEM (str) or DER (bytes) format. + :param ca_cert_data: verify the peer using concatenated CA certificate data + in PEM (str) or DER (bytes) format. {{#hasAuthMethods}} :Example: @@ -284,14 +284,14 @@ conf = {{{packageName}}}.Configuration( {{#hasHttpSignatureMethods}} signing_info: Optional[HttpSigningConfiguration]=None, {{/hasHttpSignatureMethods}} - server_index: Optional[int]=None, + server_index: Optional[int]=None, server_variables: Optional[ServerVariablesT]=None, server_operation_index: Optional[Dict[int, int]]=None, server_operation_variables: Optional[Dict[int, ServerVariablesT]]=None, ignore_operation_servers: bool=False, ssl_ca_cert: Optional[str]=None, retries: Optional[int] = None, - ca_cert_data: Optional[str | bytes] = None, + ca_cert_data: Optional[Union[str, bytes]] = None, *, debug: Optional[bool] = None, ) -> None: diff --git a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py index ce10b7eb4af6..d1ae379ac7b1 100644 --- a/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py +++ b/samples/client/echo_api/python-disallowAdditionalPropertiesIfNotPresent/openapi_client/configuration.py @@ -19,7 +19,7 @@ from logging import FileHandler import multiprocessing import sys -from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict +from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union from typing_extensions import NotRequired, Self import urllib3 @@ -163,8 +163,8 @@ class Configuration: :param ssl_ca_cert: str - the path to a file of concatenated CA certificates in PEM format. :param retries: Number of retries for API requests. - :param ca_cert_data: str|bytes - verify the peer using concatenated CA - certificate data in PEM (str) or DER (bytes) format. + :param ca_cert_data: verify the peer using concatenated CA certificate data + in PEM (str) or DER (bytes) format. :Example: @@ -195,14 +195,14 @@ def __init__( username: Optional[str]=None, password: Optional[str]=None, access_token: Optional[str]=None, - server_index: Optional[int]=None, + server_index: Optional[int]=None, server_variables: Optional[ServerVariablesT]=None, server_operation_index: Optional[Dict[int, int]]=None, server_operation_variables: Optional[Dict[int, ServerVariablesT]]=None, ignore_operation_servers: bool=False, ssl_ca_cert: Optional[str]=None, retries: Optional[int] = None, - ca_cert_data: Optional[str | bytes] = None, + ca_cert_data: Optional[Union[str, bytes]] = None, *, debug: Optional[bool] = None, ) -> None: diff --git a/samples/client/echo_api/python/openapi_client/configuration.py b/samples/client/echo_api/python/openapi_client/configuration.py index ce10b7eb4af6..d1ae379ac7b1 100644 --- a/samples/client/echo_api/python/openapi_client/configuration.py +++ b/samples/client/echo_api/python/openapi_client/configuration.py @@ -19,7 +19,7 @@ from logging import FileHandler import multiprocessing import sys -from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict +from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union from typing_extensions import NotRequired, Self import urllib3 @@ -163,8 +163,8 @@ class Configuration: :param ssl_ca_cert: str - the path to a file of concatenated CA certificates in PEM format. :param retries: Number of retries for API requests. - :param ca_cert_data: str|bytes - verify the peer using concatenated CA - certificate data in PEM (str) or DER (bytes) format. + :param ca_cert_data: verify the peer using concatenated CA certificate data + in PEM (str) or DER (bytes) format. :Example: @@ -195,14 +195,14 @@ def __init__( username: Optional[str]=None, password: Optional[str]=None, access_token: Optional[str]=None, - server_index: Optional[int]=None, + server_index: Optional[int]=None, server_variables: Optional[ServerVariablesT]=None, server_operation_index: Optional[Dict[int, int]]=None, server_operation_variables: Optional[Dict[int, ServerVariablesT]]=None, ignore_operation_servers: bool=False, ssl_ca_cert: Optional[str]=None, retries: Optional[int] = None, - ca_cert_data: Optional[str | bytes] = None, + ca_cert_data: Optional[Union[str, bytes]] = None, *, debug: Optional[bool] = None, ) -> None: diff --git a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/configuration.py b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/configuration.py index 3ddcd1cafd8d..5738e19cf7bc 100644 --- a/samples/openapi3/client/petstore/python-aiohttp/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python-aiohttp/petstore_api/configuration.py @@ -17,7 +17,7 @@ import logging from logging import FileHandler import sys -from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict +from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union from typing_extensions import NotRequired, Self import urllib3 @@ -168,8 +168,8 @@ class Configuration: :param ssl_ca_cert: str - the path to a file of concatenated CA certificates in PEM format. :param retries: Number of retries for API requests. - :param ca_cert_data: str|bytes - verify the peer using concatenated CA - certificate data in PEM (str) or DER (bytes) format. + :param ca_cert_data: verify the peer using concatenated CA certificate data + in PEM (str) or DER (bytes) format. :Example: @@ -259,14 +259,14 @@ def __init__( password: Optional[str]=None, access_token: Optional[str]=None, signing_info: Optional[HttpSigningConfiguration]=None, - server_index: Optional[int]=None, + server_index: Optional[int]=None, server_variables: Optional[ServerVariablesT]=None, server_operation_index: Optional[Dict[int, int]]=None, server_operation_variables: Optional[Dict[int, ServerVariablesT]]=None, ignore_operation_servers: bool=False, ssl_ca_cert: Optional[str]=None, retries: Optional[int] = None, - ca_cert_data: Optional[str | bytes] = None, + ca_cert_data: Optional[Union[str, bytes]] = None, *, debug: Optional[bool] = None, ) -> None: diff --git a/samples/openapi3/client/petstore/python/petstore_api/configuration.py b/samples/openapi3/client/petstore/python/petstore_api/configuration.py index a78b6698ea91..cb081f807f50 100755 --- a/samples/openapi3/client/petstore/python/petstore_api/configuration.py +++ b/samples/openapi3/client/petstore/python/petstore_api/configuration.py @@ -18,7 +18,7 @@ from logging import FileHandler import multiprocessing import sys -from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict +from typing import Any, ClassVar, Dict, List, Literal, Optional, TypedDict, Union from typing_extensions import NotRequired, Self import urllib3 @@ -169,8 +169,8 @@ class Configuration: :param ssl_ca_cert: str - the path to a file of concatenated CA certificates in PEM format. :param retries: Number of retries for API requests. - :param ca_cert_data: str|bytes - verify the peer using concatenated CA - certificate data in PEM (str) or DER (bytes) format. + :param ca_cert_data: verify the peer using concatenated CA certificate data + in PEM (str) or DER (bytes) format. :Example: @@ -260,14 +260,14 @@ def __init__( password: Optional[str]=None, access_token: Optional[str]=None, signing_info: Optional[HttpSigningConfiguration]=None, - server_index: Optional[int]=None, + server_index: Optional[int]=None, server_variables: Optional[ServerVariablesT]=None, server_operation_index: Optional[Dict[int, int]]=None, server_operation_variables: Optional[Dict[int, ServerVariablesT]]=None, ignore_operation_servers: bool=False, ssl_ca_cert: Optional[str]=None, retries: Optional[int] = None, - ca_cert_data: Optional[str | bytes] = None, + ca_cert_data: Optional[Union[str, bytes]] = None, *, debug: Optional[bool] = None, ) -> None: