diff options
author | Davanum Srinivas <dims@linux.vnet.ibm.com> | 2013-07-02 09:08:29 -0400 |
---|---|---|
committer | Davanum Srinivas <dims@linux.vnet.ibm.com> | 2013-07-08 08:58:58 -0400 |
commit | 99b7c354271e2ed0893b3c48c7f2a58a55b59b11 (patch) | |
tree | 303737580276d57f3a81963bef440ff77f8f987b | |
parent | abfd8ca6ca13b8ad1d42f081aaf29ec639a4032c (diff) | |
download | oslo-99b7c354271e2ed0893b3c48c7f2a58a55b59b11.tar.gz oslo-99b7c354271e2ed0893b3c48c7f2a58a55b59b11.tar.xz oslo-99b7c354271e2ed0893b3c48c7f2a58a55b59b11.zip |
Convert kombu SSL version string into integer
When specifying 'kombu_ssl_version' for the RPC driver such as either
"kombu_ssl_version=3" or "kombu_ssl_version=SSLv3" the relevant
OpenStack service (nova, cinder, etc) will fail as the underlying
rpc driver is trying to create an SSL socket which requires an
integer such as the following built-in SSL integer constants. Added
a validation step that ensures one can set only the supported ssl
versions and to convert from the specified string to an integer
Fixes LP# 1195431
Change-Id: I5d188f46a15bc4ba60d573d6b98def60c56cb987
-rw-r--r-- | openstack/common/rpc/impl_kombu.py | 9 | ||||
-rw-r--r-- | openstack/common/sslutils.py | 20 | ||||
-rw-r--r-- | tests/unit/rpc/test_kombu_ssl.py | 25 | ||||
-rw-r--r-- | tests/unit/test_sslutils.py | 66 |
4 files changed, 116 insertions, 4 deletions
diff --git a/openstack/common/rpc/impl_kombu.py b/openstack/common/rpc/impl_kombu.py index 36d2fc5..70f19b4 100644 --- a/openstack/common/rpc/impl_kombu.py +++ b/openstack/common/rpc/impl_kombu.py @@ -34,11 +34,15 @@ from openstack.common.gettextutils import _ from openstack.common import network_utils from openstack.common.rpc import amqp as rpc_amqp from openstack.common.rpc import common as rpc_common +from openstack.common import sslutils kombu_opts = [ cfg.StrOpt('kombu_ssl_version', default='', - help='SSL version to use (valid only if SSL enabled)'), + help='SSL version to use (valid only if SSL enabled). ' + 'valid values are TLSv1, SSLv23 and SSLv3. SSLv2 may ' + 'be available on some distributions' + ), cfg.StrOpt('kombu_ssl_keyfile', default='', help='SSL key file (valid only if SSL enabled)'), @@ -477,7 +481,8 @@ class Connection(object): # http://docs.python.org/library/ssl.html - ssl.wrap_socket if self.conf.kombu_ssl_version: - ssl_params['ssl_version'] = self.conf.kombu_ssl_version + ssl_params['ssl_version'] = sslutils.validate_ssl_version( + self.conf.kombu_ssl_version) if self.conf.kombu_ssl_keyfile: ssl_params['keyfile'] = self.conf.kombu_ssl_keyfile if self.conf.kombu_ssl_certfile: diff --git a/openstack/common/sslutils.py b/openstack/common/sslutils.py index 252da72..281684b 100644 --- a/openstack/common/sslutils.py +++ b/openstack/common/sslutils.py @@ -78,3 +78,23 @@ def wrap(sock): ssl_kwargs['cert_reqs'] = ssl.CERT_REQUIRED return ssl.wrap_socket(sock, **ssl_kwargs) + + +_SSL_PROTOCOLS = { + "tlsv1": ssl.PROTOCOL_TLSv1, + "sslv23": ssl.PROTOCOL_SSLv23, + "sslv3": ssl.PROTOCOL_SSLv3 +} + +try: + _SSL_PROTOCOLS["sslv2"] = ssl.PROTOCOL_SSLv2 +except AttributeError: + pass + + +def validate_ssl_version(version): + key = version.lower() + try: + return _SSL_PROTOCOLS[key] + except KeyError: + raise RuntimeError(_("Invalid SSL version : %s") % version) diff --git a/tests/unit/rpc/test_kombu_ssl.py b/tests/unit/rpc/test_kombu_ssl.py index 688c992..2a0b170 100644 --- a/tests/unit/rpc/test_kombu_ssl.py +++ b/tests/unit/rpc/test_kombu_ssl.py @@ -20,6 +20,7 @@ Unit Tests for remote procedure calls using kombu + ssl """ import eventlet +import ssl eventlet.monkey_patch() from oslo.config import cfg @@ -36,7 +37,7 @@ except ImportError: # Flag settings we will ensure get passed to amqplib -SSL_VERSION = "SSLv2" +SSL_VERSION = "SSLv3" SSL_CERT = "/tmp/cert.blah.blah" SSL_CA_CERT = "/tmp/cert.ca.blah.blah" SSL_KEYFILE = "/tmp/keyfile.blah.blah" @@ -64,9 +65,29 @@ class RpcKombuSslTestCase(test_utils.BaseTestCase): #This might be kombu version dependent... #Since we are now peaking into the internals of kombu... self.assertTrue(isinstance(c.connection.ssl, dict)) - self.assertEqual(SSL_VERSION, c.connection.ssl.get("ssl_version")) + self.assertEqual(ssl.PROTOCOL_SSLv3, + c.connection.ssl.get("ssl_version")) self.assertEqual(SSL_CERT, c.connection.ssl.get("certfile")) self.assertEqual(SSL_CA_CERT, c.connection.ssl.get("ca_certs")) self.assertEqual(SSL_KEYFILE, c.connection.ssl.get("keyfile")) #That hash then goes into amqplib which then goes #Into python ssl creation... + + +class RpcKombuSslBadVersionTestCase(test_utils.BaseTestCase): + + def setUp(self): + super(RpcKombuSslBadVersionTestCase, self).setUp() + if kombu is None: + self.skipTest("Test requires kombu") + self.config(kombu_ssl_keyfile=SSL_KEYFILE, + kombu_ssl_ca_certs=SSL_CA_CERT, + kombu_ssl_certfile=SSL_CERT, + kombu_ssl_version="SSLv24", + rabbit_use_ssl=True, + fake_rabbit=True) + + def test_bad_ssl_version(self): + rpc = impl_kombu + self.assertRaises(RuntimeError, + rpc.create_connection, FLAGS, True) diff --git a/tests/unit/test_sslutils.py b/tests/unit/test_sslutils.py new file mode 100644 index 0000000..4c0646e --- /dev/null +++ b/tests/unit/test_sslutils.py @@ -0,0 +1,66 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 IBM Corp. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import ssl + +from openstack.common import sslutils +from tests import utils + + +class SSLUtilsTest(utils.BaseTestCase): + def test_valid_versions(self): + self.assertEquals(sslutils.validate_ssl_version("SSLv3"), + ssl.PROTOCOL_SSLv3) + self.assertEquals(sslutils.validate_ssl_version("SSLv23"), + ssl.PROTOCOL_SSLv23) + self.assertEquals(sslutils.validate_ssl_version("TLSv1"), + ssl.PROTOCOL_TLSv1) + try: + protocol = ssl.PROTOCOL_SSLv2 + except AttributeError: + pass + else: + self.assertEquals(sslutils.validate_ssl_version("SSLv2"), + protocol) + + def test_lowercase_valid_versions(self): + self.assertEquals(sslutils.validate_ssl_version("sslv3"), + ssl.PROTOCOL_SSLv3) + self.assertEquals(sslutils.validate_ssl_version("sslv23"), + ssl.PROTOCOL_SSLv23) + self.assertEquals(sslutils.validate_ssl_version("tlsv1"), + ssl.PROTOCOL_TLSv1) + try: + protocol = ssl.PROTOCOL_SSLv2 + except AttributeError: + pass + else: + self.assertEquals(sslutils.validate_ssl_version("sslv2"), + protocol) + + def test_invalid_version(self): + self.assertRaises(RuntimeError, + sslutils.validate_ssl_version, + "v3") + + # Some distributions do not have SSLv2 enabled, make sure + # we throw a runtime error + try: + ssl.PROTOCOL_SSLv2 + except AttributeError: + self.assertRaises(RuntimeError, + sslutils.validate_ssl_version, + "SSLv2") |