Merge pull request #478 from tianhao64/master

Fix thumbprint verification
This commit is contained in:
Tianhao He 2016-11-14 17:40:11 -08:00 committed by GitHub
commit 46f5ecaebb
8 changed files with 67 additions and 59 deletions

View File

@ -942,8 +942,6 @@ class SoapStubAdapterBase(StubAdapterBase):
## Subclass of HTTPConnection that connects over a Unix domain socket
## instead of a TCP port. The path of the socket is passed in place of
## the hostname. Fairly gross but does the job.
# NOTE (hartsock): rewrite this class as a wrapper, see HTTPSConnectionWrapper
# below for a guide.
class UnixSocketConnection(http_client.HTTPConnection):
# The HTTPConnection ctor expects a single argument, which it interprets
# as the host to connect to; for UnixSocketConnection, we instead interpret
@ -999,20 +997,14 @@ except ImportError:
wrappedSocket = socket.ssl(rawSocket, keyfile, certfile)
return http_client.FakeSocket(rawSocket, wrappedSocket)
## https connection wrapper
## Internal version of https connection
#
# NOTE (hartsock): do not override core library types or implementations
# directly because this makes brittle code that is too easy to break and
# closely tied to implementation details we do not control. Instead, wrap
# the core object to introduce additional behaviors.
#
# Purpose:
# Support ssl.wrap_socket params which are missing from httplib
# HTTPSConnection (e.g. ca_certs)
# Note: Only works iff the ssl params are passing in as kwargs
class HTTPSConnectionWrapper(object):
# Note: Only works if the ssl params are passing in as kwargs
class _HTTPSConnection(http_client.HTTPSConnection):
def __init__(self, *args, **kwargs):
wrapped = http_client.HTTPSConnection(*args, **kwargs)
# Extract ssl.wrap_socket param unknown to httplib.HTTPSConnection,
# and push back the params in connect()
self._sslArgs = {}
@ -1022,14 +1014,15 @@ class HTTPSConnectionWrapper(object):
"ciphers"]:
if key in tmpKwargs:
self._sslArgs[key] = tmpKwargs.pop(key)
self._wrapped = wrapped
http_client.HTTPSConnection.__init__(self, *args, **tmpKwargs)
## Override connect to allow us to pass in additional ssl paramters to
# ssl.wrap_socket (e.g. cert_reqs, ca_certs for ca cert verification)
def connect(self, wrapped):
if len(self._sslArgs) == 0 or hasattr(self, '_baseclass'):
def connect(self):
if len(self._sslArgs) == 0:
# No override
return wrapped.connect
http_client.HTTPSConnection.connect(self)
return
# Big hack. We have to copy and paste the httplib connect fn for
# each python version in order to handle extra ssl paramters. Yuk!
@ -1037,30 +1030,34 @@ class HTTPSConnectionWrapper(object):
# Python 2.7
sock = socket.create_connection((self.host, self.port),
self.timeout, self.source_address)
if wrapped._tunnel_host:
wrapped.sock = sock
wrapped._tunnel()
wrapped.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, **self._sslArgs)
if self._tunnel_host:
self.sock = sock
self._tunnel()
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
**self._sslArgs)
elif hasattr(self, "timeout"):
# Python 2.6
sock = socket.create_connection((self.host, self.port), self.timeout)
wrapped.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, **self._sslArgs)
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
**self._sslArgs)
else:
# Unknown python version. Do nothing
http_client.HTTPSConnection.connect(self)
return
return wrapped.connect
# TODO: Additional verification of peer cert if needed
#cert_reqs = self._sslArgs.get("cert_reqs", ssl.CERT_NONE)
#ca_certs = self._sslArgs.get("ca_certs", None)
#if cert_reqs != ssl.CERT_NONE and ca_certs:
# if hasattr(self.sock, "getpeercert"):
# # TODO: verify peer cert
# dercert = self.sock.getpeercert(False)
# # pemcert = ssl.DER_cert_to_PEM_cert(dercert)
# TODO: Additional verification of peer cert if needed
# cert_reqs = self._sslArgs.get("cert_reqs", ssl.CERT_NONE)
# ca_certs = self._sslArgs.get("ca_certs", None)
# if cert_reqs != ssl.CERT_NONE and ca_certs:
# if hasattr(self.sock, "getpeercert"):
# # TODO: verify peer cert
# dercert = self.sock.getpeercert(False)
# # pemcert = ssl.DER_cert_to_PEM_cert(dercert)
def __getattr__(self, item):
if item == 'connect':
return self.connect(self._wrapped)
return getattr(self._wrapped, item)
if item == 'connect':
return self.connect(self._wrapped)
return getattr(self._wrapped, item)
## Stand-in for the HTTPSConnection class that will connect to a proxy and
## issue a CONNECT command to start an SSL tunnel.
@ -1222,10 +1219,10 @@ class SoapStubAdapter(SoapStubAdapterBase):
if urlpath not in ('', '/'):
path = urlpath
self.scheme = scheme == "http" and http_client.HTTPConnection \
or scheme == "https" and HTTPSConnectionWrapper
or scheme == "https" and _HTTPSConnection
else:
port, self.scheme = port < 0 and (-port, http_client.HTTPConnection) \
or (port, HTTPSConnectionWrapper)
or (port, _HTTPSConnection)
if host.find(':') != -1: # is IPv6?
host = '[' + host + ']'
self.host = '{0}:{1}'.format(host, port)
@ -1243,7 +1240,7 @@ class SoapStubAdapter(SoapStubAdapterBase):
self.scheme = SSLTunnelConnection(sslProxyPath)
self.is_ssl_tunnel = True
elif httpProxyHost:
if self.scheme == HTTPSConnectionWrapper:
if self.scheme == _HTTPSConnection:
self.scheme = SSLTunnelConnection(self.host)
self.is_ssl_tunnel = True
else:
@ -1279,7 +1276,7 @@ class SoapStubAdapter(SoapStubAdapterBase):
# depend on the behavior that close() still leaves the socket semi-functional.
if sys.version_info[:2] < (2,7):
def _CloseConnection(self, conn):
if self.scheme == HTTPSConnectionWrapper and conn.sock:
if self.scheme == _HTTPSConnection and conn.sock:
conn.sock.shutdown(socket.SHUT_RDWR)
conn.close()
else:

View File

@ -14,9 +14,14 @@
# limitations under the License.
import logging
import os
import unittest
import vcr
import socket
import unittest
import vcr
from vcr import config
from vcr.stubs import VCRHTTPSConnection
from pyVmomi import SoapAdapter
def tests_resource_path(local_path=''):
@ -33,6 +38,8 @@ def monkey_patch_vcrpy():
vcr.stubs.VCRFakeSocket = socket.socket
class VCRTestBase(unittest.TestCase):
my_vcr = config.VCR(
custom_patches=((SoapAdapter, '_HTTPSConnection', VCRHTTPSConnection),))
def setUp(self):
monkey_patch_vcrpy()

View File

@ -15,7 +15,6 @@
import tests
import unittest
import vcr
from pyVim import connect
from pyVmomi import vim
@ -23,7 +22,7 @@ from pyVmomi import vim
class ConnectionTests(tests.VCRTestBase):
@vcr.use_cassette('basic_connection.yaml',
@tests.VCRTestBase.my_vcr.use_cassette('basic_connection.yaml',
cassette_library_dir=tests.fixtures_path,
record_mode='none')
def test_basic_connection(self):
@ -40,7 +39,7 @@ class ConnectionTests(tests.VCRTestBase):
self.assertTrue(session_id is not None)
self.assertEqual('52b5395a-85c2-9902-7835-13a9b77e1fec', session_id)
@vcr.use_cassette('sspi_connection.yaml',
@tests.VCRTestBase.my_vcr.use_cassette('sspi_connection.yaml',
cassette_library_dir=tests.fixtures_path,
record_mode='none')
def test_sspi_connection(self):
@ -57,7 +56,7 @@ class ConnectionTests(tests.VCRTestBase):
self.assertTrue(session_id is not None)
self.assertEqual('52b5395a-85c2-9902-7835-13a9b77e1fec', session_id)
@vcr.use_cassette('basic_connection_bad_password.yaml',
@tests.VCRTestBase.my_vcr.use_cassette('basic_connection_bad_password.yaml',
cassette_library_dir=tests.fixtures_path,
record_mode='none')
def test_basic_connection_bad_password(self):
@ -68,7 +67,7 @@ class ConnectionTests(tests.VCRTestBase):
self.assertRaises(vim.fault.InvalidLogin, should_fail)
@vcr.use_cassette('smart_connection.yaml',
@tests.VCRTestBase.my_vcr.use_cassette('smart_connection.yaml',
cassette_library_dir=tests.fixtures_path,
record_mode='none')
def test_smart_connection(self):
@ -84,13 +83,13 @@ class ConnectionTests(tests.VCRTestBase):
def test_disconnect_on_no_connection(self):
connect.Disconnect(None)
@vcr.use_cassette('ssl_tunnel.yaml',
@tests.VCRTestBase.my_vcr.use_cassette('ssl_tunnel.yaml',
cassette_library_dir=tests.fixtures_path,
record_mode='none')
def test_ssl_tunnel(self):
connect.SoapStubAdapter('sdkTunnel', 8089, httpProxyHost='vcsa').GetConnection()
@vcr.use_cassette('ssl_tunnel_http_failure.yaml',
@tests.VCRTestBase.my_vcr.use_cassette('ssl_tunnel_http_failure.yaml',
cassette_library_dir=tests.fixtures_path,
record_mode='none')
def test_ssl_tunnel_http_failure(self):

View File

@ -13,7 +13,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import tests
import vcr
from pyVim import connect
from pyVmomi import vim
@ -21,7 +20,7 @@ from pyVmomi import vim
class ContainerViewTests(tests.VCRTestBase):
@vcr.use_cassette('basic_container_view.yaml',
@tests.VCRTestBase.my_vcr.use_cassette('basic_container_view.yaml',
cassette_library_dir=tests.fixtures_path,
record_mode='once')
def test_basic_container_view(self):

View File

@ -16,15 +16,18 @@ from datetime import datetime
from datetime import timedelta
import tests
import vcr
from pyVim import connect
from pyVmomi.Iso8601 import TZManager
from pyVmomi import SoapAdapter
from vcr.stubs import VCRHTTPSConnection
from vcr import config
class Iso8601Tests(tests.VCRTestBase):
@vcr.use_cassette('test_vm_config_iso8601.yaml',
@tests.VCRTestBase.my_vcr.use_cassette('test_vm_config_iso8601.yaml',
cassette_library_dir=tests.fixtures_path,
record_mode='once')
def test_vm_config_iso8601(self):
@ -76,7 +79,9 @@ class Iso8601Tests(tests.VCRTestBase):
return False
return True
my_vcr = vcr.VCR()
my_vcr = config.VCR(
custom_patches=(
(SoapAdapter, '_HTTPSConnection', VCRHTTPSConnection),))
my_vcr.register_matcher('document', check_date_time_value)
# NOTE (hartsock): the `match_on` option is altered to use the

View File

@ -15,14 +15,13 @@
from __future__ import print_function
import tests
import vcr
from pyVim import connect
class ManagedObjectTests(tests.VCRTestBase):
@vcr.use_cassette('root_folder_parent.yaml',
@tests.VCRTestBase.my_vcr.use_cassette('root_folder_parent.yaml',
cassette_library_dir=tests.fixtures_path,
record_mode='once')
def test_root_folder_parent(self):

View File

@ -13,8 +13,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import tests
import vcr
from vcr.stubs import VCRHTTPSConnection
from vcr import config
from pyVmomi import SoapAdapter
from pyVmomi import SoapStubAdapter
@ -22,6 +22,7 @@ from pyVmomi import vim
from pyVmomi.VmomiSupport import GetRequestContext
class SerializerTests(tests.VCRTestBase):
def test_serialize_object(self):
val = vim.vm.device.VirtualDeviceSpec.FileOperation()
@ -40,7 +41,9 @@ class SerializerTests(tests.VCRTestBase):
SoapAdapter.Serialize(pc, version='vim.version.version10')
def _base_serialize_test(self, soap_creator, request_matcher):
my_vcr = vcr.VCR()
my_vcr = config.VCR(
custom_patches=(
(SoapAdapter, '_HTTPSConnection', VCRHTTPSConnection),))
my_vcr.register_matcher('request_matcher', request_matcher)
with my_vcr.use_cassette(

View File

@ -15,7 +15,6 @@
from __future__ import print_function
import tests
import vcr
from pyVim import connect
from pyVmomi import vim
@ -23,7 +22,7 @@ from pyVmomi import vim
class VirtualMachineTests(tests.VCRTestBase):
@vcr.use_cassette('vm_nic_data.yaml',
@tests.VCRTestBase.my_vcr.use_cassette('vm_nic_data.yaml',
cassette_library_dir=tests.fixtures_path,
record_mode='never')
def test_vm_nic_data(self):