Add SSL cert verification regression tests

A security bug (1357430) was introduced which meant that SSL certificate
verification was not occurring.

Add new tests which help prevent the 'requests' part of bug 115260
recurring.

Note: Cherry-picking onto the stable branch -- these tests are required
      for proper testing of one of the SSL related fixes.

Change-Id: Iaf56fd8bc34fa8f35c2fd7051f9f8424002352cf
Related-bug: 1357430
(cherry picked from commit 64a1a0fdcc)
This commit is contained in:
Stuart McLaren 2014-08-20 15:58:44 +00:00
parent 7184759029
commit e572ec1d1f
1 changed files with 106 additions and 19 deletions

View File

@ -20,42 +20,102 @@ try:
from requests.packages.urllib3 import poolmanager from requests.packages.urllib3 import poolmanager
except ImportError: except ImportError:
from urllib3 import poolmanager from urllib3 import poolmanager
import six
import ssl
import testtools import testtools
import threading
from glanceclient.common import http from glanceclient.common import http
from glanceclient.common import https from glanceclient.common import https
from glanceclient import Client
from glanceclient import exc from glanceclient import exc
if six.PY3 is True:
import socketserver
else:
import SocketServer as socketserver
TEST_VAR_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), TEST_VAR_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__),
'var')) 'var'))
class TestRequestsIntegration(testtools.TestCase): class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
self.request.recv(1024)
response = b'somebytes'
self.request.sendall(response)
def test_pool_patch(self):
client = http.HTTPClient("https://localhost",
ssl_compression=True)
self.assertNotEqual(https.HTTPSConnectionPool,
poolmanager.pool_classes_by_scheme["https"])
adapter = client.session.adapters.get("https://") class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
self.assertFalse(isinstance(adapter, https.HTTPSAdapter)) def get_request(self):
key_file = os.path.join(TEST_VAR_DIR, 'privatekey.key')
cert_file = os.path.join(TEST_VAR_DIR, 'certificate.crt')
cacert = os.path.join(TEST_VAR_DIR, 'ca.crt')
(_sock, addr) = socketserver.TCPServer.get_request(self)
sock = ssl.wrap_socket(_sock,
certfile=cert_file,
keyfile=key_file,
ca_certs=cacert,
server_side=True,
cert_reqs=ssl.CERT_REQUIRED)
return sock, addr
adapter = client.session.adapters.get("glance+https://")
self.assertFalse(isinstance(adapter, https.HTTPSAdapter))
def test_custom_https_adapter(self): class TestHTTPSVerifyCert(testtools.TestCase):
client = http.HTTPClient("https://localhost", """Check 'requests' based ssl verification occurs
ssl_compression=False)
self.assertNotEqual(https.HTTPSConnectionPool,
poolmanager.pool_classes_by_scheme["https"])
adapter = client.session.adapters.get("https://") The requests library performs SSL certificate validation,
self.assertFalse(isinstance(adapter, https.HTTPSAdapter)) however there is still a need to check that the glance
client is properly integrated with requests so that
cert validation actually happens.
"""
def setUp(self):
# Rather than spinning up a new process, we create
# a thread to perform client/server interaction.
# This should run more quickly.
super(TestHTTPSVerifyCert, self).setUp()
server = ThreadedTCPServer(('127.0.0.1', 0),
ThreadedTCPRequestHandler)
__, self.port = server.server_address
server_thread = threading.Thread(target=server.serve_forever)
server_thread.daemon = True
server_thread.start()
adapter = client.session.adapters.get("glance+https://") def test_v1_requests_cert_verification(self):
self.assertTrue(isinstance(adapter, https.HTTPSAdapter)) """v1 regression test for bug 115260."""
port = self.port
url = 'https://0.0.0.0:%d' % port
try:
client = Client('1', url,
insecure=False,
ssl_compression=True)
client.images.get('image123')
self.fail('No SSL exception raised')
except exc.CommunicationError as e:
if 'certificate verify failed' not in e.message:
self.fail('No certificate failure message received')
except Exception as e:
self.fail('Unexpected exception raised')
def test_v2_requests_cert_verification(self):
"""v2 regression test for bug 115260."""
port = self.port
url = 'https://0.0.0.0:%d' % port
try:
gc = Client('2', url,
insecure=False,
ssl_compression=True)
gc.images.get('image123')
self.fail('No SSL exception raised')
except exc.CommunicationError as e:
if 'certificate verify failed' not in e.message:
self.fail('No certificate failure message received')
except Exception as e:
self.fail('Unexpected exception raised')
class TestVerifiedHTTPSConnection(testtools.TestCase): class TestVerifiedHTTPSConnection(testtools.TestCase):
@ -328,3 +388,30 @@ class TestVerifiedHTTPSConnection(testtools.TestCase):
cacert=cacert) cacert=cacert)
except exc.SSLConfigurationError: except exc.SSLConfigurationError:
self.fail('Failed to init VerifiedHTTPSConnection.') self.fail('Failed to init VerifiedHTTPSConnection.')
class TestRequestsIntegration(testtools.TestCase):
def test_pool_patch(self):
client = http.HTTPClient("https://localhost",
ssl_compression=True)
self.assertNotEqual(https.HTTPSConnectionPool,
poolmanager.pool_classes_by_scheme["https"])
adapter = client.session.adapters.get("https://")
self.assertFalse(isinstance(adapter, https.HTTPSAdapter))
adapter = client.session.adapters.get("glance+https://")
self.assertFalse(isinstance(adapter, https.HTTPSAdapter))
def test_custom_https_adapter(self):
client = http.HTTPClient("https://localhost",
ssl_compression=False)
self.assertNotEqual(https.HTTPSConnectionPool,
poolmanager.pool_classes_by_scheme["https"])
adapter = client.session.adapters.get("https://")
self.assertFalse(isinstance(adapter, https.HTTPSAdapter))
adapter = client.session.adapters.get("glance+https://")
self.assertTrue(isinstance(adapter, https.HTTPSAdapter))