[go: nahoru, domu]

Skip to content

Commit

Permalink
Python 3.12 compatibility - closes #1057
Browse files Browse the repository at this point in the history
There are two Python 3.12 changes that affect the pyVmomi client
- Python 3.12 removes ssl.wrap_socket(), deprecated in Python 3.7. ssl.SSLContext.wrap_socket() should be used instead. Ref. https://docs.python.org/3/whatsnew/3.12.html#ssl
- key_file, cert_file are removed from http.client.HTTPSConnection. Ref. https://docs.python.org/3/whatsnew/3.12.html#others

This change:
- The connection logic is refactored to comply with the new Python rules. Python now forces users to generate the SSL context on their own. However, the SoapStubAdapter still has to accept the cert and key pair and SSL context at the same time to keep backwards compatibility for all existing tests and clients.
To do that, instead of relying on the http module to generate the SSL context if none is provided, the SoapStubAdapter now handles that generation by mirroring the http module code before the Python 3.12 changes. Because the SSL context generation is pulled to be executed as early as possible there is no need to figure out what parameters are acceptable to pass to the Python http module because the context is already generated. Therefore, the HTTP connection wrappers can be removed - _HTTPConnection and _HTTPSConnection.

- ssl.create_default_context() is replaced with SSL._create_default_https_context() to mirror the HTTP module logic.
	This change is propagated to the sso.py module to keep the behavior consistent.

Additional changes:
Breaking change:
- SSLTunnelConnection is trimmed down to handle only tunnel connections. The code that handles remote proxy doubles the HTTPProxyConnection logic and therefore is removed.
  This is a breaking change for consumers that wrongly set "sslProxyPath" instead of "httpProxyHost" when they want to go through a remote proxy but I consider this a necessary change because allowing this behavior is a bug and shouldn't have been available at first place.

Non-breaking changes:
- SSLTunnelConnection now inherits HTTPProxyConnection and overwrites the call method because the constructor is the same. Keep in mind that it's deprecated. Hopefully it will be removed sooner rather than later.

- _CheckIPv4(), _CheckIPv6() and _CheckHostname() are removed because it's not necessary to make those verifications when SSLTunnelConnection does not support remote proxies.

- Small changes to variable names and imports
  • Loading branch information
ddraganov committed May 14, 2024
1 parent c248b32 commit 44d7b9f
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 252 deletions.
67 changes: 21 additions & 46 deletions pyVim/sso.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
#############################################################
# Copyright (c) 2012-2024 VMware, Inc.
# Copyright (c) 2012-2024 Broadcom. All Rights Reserved.
# The term "Broadcom" refers to Broadcom Inc.
# and/or its subsidiaries.
# A python helper module to do SSO related operations.
#############################################################
__author__ = 'VMware, Inc.'

#Standard library imports.
import six.moves.http_client
from six.moves.http_client import HTTPConnection, HTTPSConnection
import re
from six import PY3
if PY3:
Expand Down Expand Up @@ -101,30 +103,11 @@ def __str__(self):
"faultxml: %(_soap_msg)s" % self.__dict__)


class SSOHTTPConnection(six.moves.http_client.HTTPConnection):
"""
A class that establishes HTTP Connection.
Only intened to be used for calls routing through
a local sidecar proxy (localhost:1080).
"""
def __init__(self, *args, **kwargs):
"""
Initializer. See httplib.HTTPConnection for other arguments
"""
tmpKwargs = {}
httpConn = six.moves.http_client.HTTPConnection
for key in httpConn.__init__.__code__.co_varnames:
if key in kwargs and key != 'self':
tmpKwargs[key] = kwargs[key]
self.host = kwargs.pop('host')
six.moves.http_client.HTTPConnection.__init__(self, *args, **tmpKwargs)


class SSOHTTPSConnection(six.moves.http_client.HTTPSConnection):
class _SSOHTTPSConnection(HTTPSConnection):
"""
An HTTPS class that verifies server's certificate on connect.
"""
def __init__(self, *args, **kwargs):
def __init__(self, host, context, thumbprint=None, server_cert=None):
"""
Initializer. See httplib.HTTPSConnection for other arguments
than thumbprint and server_cert.
Expand All @@ -140,18 +123,18 @@ def __init__(self, *args, **kwargs):
@param server_cert: File with expected server certificate.
May be None.
"""
self.server_thumbprint = kwargs.pop('thumbprint')
self.server_thumbprint = thumbprint
if self.server_thumbprint is not None:
self.server_thumbprint = re.sub(':', '',
self.server_thumbprint.lower())
server_cert_path = kwargs.pop('server_cert')
server_cert_path = server_cert
if server_cert_path is not None:
with open(server_cert_path, 'rb') as f:
server_cert = f.read().decode(UTF_8)
self.server_cert = _extract_certificate(server_cert)
else:
self.server_cert = None
six.moves.http_client.HTTPSConnection.__init__(self, *args, **kwargs)
HTTPSConnection.__init__(self, host=host, context=context)

def _check_cert(self, peerCert):
"""
Expand Down Expand Up @@ -182,7 +165,7 @@ def connect(self):
Throws an exception when something is wrong. See
httplib.HTTPSConnection.connect() for details.
"""
six.moves.http_client.HTTPSConnection.connect(self)
HTTPSConnection.connect(self)

self._check_cert(self.sock.getpeercert(True))

Expand Down Expand Up @@ -240,7 +223,6 @@ def perform_request(self,
user registered with SSO, in PEM format.
@type ssl_context: C{ssl.SSLContext}
@param ssl_context: SSL context describing the various SSL options.
It is only supported in Python 2.7.9 or higher.
@rtype: C{str}
@return: Response received from the STS after the HoK request.
"""
Expand All @@ -249,29 +231,25 @@ def perform_request(self,
scheme = parsed.scheme
encoded_message = soap_message.encode(UTF_8)

if ssl_context is not None:
sslContext = ssl_context
else:
sslContext = ssl._create_default_https_context()
if public_key and private_key:
sslContext.load_cert_chain(public_key, private_key)

"""
Allow creation of HTTPConnection, only for calls routing
through local sidecar (localhost:1080)
"""
if is_sidecar_request(scheme, host):
webservice = SSOHTTPConnection(host=host)
elif hasattr(ssl, '_create_unverified_context'):
# Python 2.7.9 has stronger SSL certificate validation, so we need
# to pass in a context when dealing with self-signed certificates.
webservice = SSOHTTPSConnection(host=host,
key_file=private_key,
cert_file=public_key,
webservice = HTTPConnection(host=host)
else:
webservice = _SSOHTTPSConnection(host=host,
server_cert=self._sts_cert,
thumbprint=self._sts_thumbprint,
context=ssl_context)
else:
# Versions of Python before 2.7.9 don't support
# the context parameter, so don't pass it on.
webservice = SSOHTTPSConnection(host=host,
key_file=private_key,
cert_file=public_key,
server_cert=self._sts_cert,
thumbprint=self._sts_thumbprint)


webservice.putrequest("POST", parsed.path, skip_host=True) # pylint: disable=E1101
webservice.putheader("Host", host)
Expand Down Expand Up @@ -342,7 +320,6 @@ def get_bearer_saml_assertion(self,
The default value is False
@type ssl_context: C{ssl.SSLContext}
@param ssl_context: SSL context describing the various SSL options.
It is only supported in Python 2.7.9 or higher.
@rtype: C{str}
@return: The SAML assertion in Unicode.
"""
Expand Down Expand Up @@ -398,7 +375,6 @@ def get_hok_saml_assertion(self,
The default value is False
@type ssl_context: C{ssl.SSLContext}
@param ssl_context: SSL context describing the various SSL options.
It is only supported in Python 2.7.9 or higher.
@rtype: C{str}
@return: The SAML assertion in Unicode.
"""
Expand Down Expand Up @@ -449,7 +425,6 @@ def get_token_by_token(self,
The default value is False
@type ssl_context: C{ssl.SSLContext}
@param ssl_context: SSL context describing the various SSL options.
It is only supported in Python 2.7.9 or higher.
@rtype: C{str}
@return: The Hok SAML assertion in Unicode.
"""
Expand Down
Loading

0 comments on commit 44d7b9f

Please sign in to comment.