diff --git a/nova/api/ec2/__init__.py b/nova/api/ec2/__init__.py index 65b8dab227e9..2fa5846ef1e5 100644 --- a/nova/api/ec2/__init__.py +++ b/nova/api/ec2/__init__.py @@ -18,13 +18,12 @@ Starting point for routing EC2 requests. """ -from eventlet.green import httplib from oslo.config import cfg from oslo.serialization import jsonutils from oslo.utils import importutils from oslo.utils import timeutils +import requests import six -import six.moves.urllib.parse as urlparse import webob import webob.dec import webob.exc @@ -71,11 +70,14 @@ ec2_opts = [ cfg.IntOpt('ec2_timestamp_expiry', default=300, help='Time in seconds before ec2 timestamp expires'), + cfg.BoolOpt('keystone_ec2_insecure', default=False, help='Disable SSL ' + 'certificate verification.'), ] CONF = cfg.CONF CONF.register_opts(ec2_opts) CONF.import_opt('use_forwarded_for', 'nova.api.auth') +CONF.import_group('ssl', 'nova.openstack.common.sslutils') # Fault Wrapper around all EC2 requests @@ -216,23 +218,28 @@ class EC2KeystoneAuth(wsgi.Middleware): creds_json = jsonutils.dumps(creds) headers = {'Content-Type': 'application/json'} - o = urlparse.urlparse(CONF.keystone_ec2_url) - if o.scheme == "http": - conn = httplib.HTTPConnection(o.netloc) - else: - conn = httplib.HTTPSConnection(o.netloc) - conn.request('POST', o.path, body=creds_json, headers=headers) - response = conn.getresponse() - data = response.read() - if response.status != 200: - if response.status == 401: + verify = not CONF.keystone_ec2_insecure + if verify and CONF.ssl.ca_file: + verify = CONF.ssl.ca_file + + cert = None + if CONF.ssl.cert_file and CONF.ssl.key_file: + cert = (CONF.ssl.cert_file, CONF.ssl.key_file) + elif CONF.ssl.cert_file: + cert = CONF.ssl.cert_file + + response = requests.request('POST', CONF.keystone_ec2_url, + data=creds_json, headers=headers, + verify=verify, cert=cert) + status_code = response.status_code + if status_code != 200: + if status_code == 401: msg = response.reason else: msg = _("Failure communicating with keystone") return faults.ec2_error_response(request_id, "AuthFailure", msg, - status=response.status) - result = jsonutils.loads(data) - conn.close() + status=status_code) + result = response.json() try: token_id = result['access']['token']['id'] diff --git a/nova/tests/unit/api/ec2/test_middleware.py b/nova/tests/unit/api/ec2/test_middleware.py index 246e0d39f7d9..d813d7b75887 100644 --- a/nova/tests/unit/api/ec2/test_middleware.py +++ b/nova/tests/unit/api/ec2/test_middleware.py @@ -14,11 +14,11 @@ # License for the specific language governing permissions and limitations # under the License. -from eventlet.green import httplib from lxml import etree -from mox3 import mox +import mock from oslo.config import cfg from oslo.utils import timeutils +import requests import webob import webob.dec import webob.exc @@ -153,11 +153,11 @@ class ExecutorTestCase(test.NoDBTestCase): class FakeResponse(object): reason = "Test Reason" - def __init__(self, status=400): - self.status = status + def __init__(self, status_code=400): + self.status_code = status_code - def read(self): - return '{}' + def json(self): + return {} class KeystoneAuthTestCase(test.NoDBTestCase): @@ -188,38 +188,24 @@ class KeystoneAuthTestCase(test.NoDBTestCase): resp = self.kauth(req) self._validate_ec2_error(resp, 400, 'AuthFailure') - def test_communication_failure(self): + @mock.patch.object(requests, 'request', return_value=FakeResponse()) + def test_communication_failure(self, mock_request): req = wsgi.Request.blank('/test') req.GET['Signature'] = 'test-signature' req.GET['AWSAccessKeyId'] = 'test-key-id' - - conn = httplib.HTTPConnection('/mock') - self.mox.StubOutWithMock(httplib.HTTPConnection, 'request') - self.mox.StubOutWithMock(httplib.HTTPConnection, 'getresponse') - conn.request('POST', mox.IgnoreArg(), body=mox.IgnoreArg(), - headers=mox.IgnoreArg()) - resp = FakeResponse() - conn.getresponse().AndReturn(resp) - self.mox.ReplayAll() - resp = self.kauth(req) self._validate_ec2_error(resp, 400, 'AuthFailure') + mock_request.assert_called_with('POST', CONF.keystone_ec2_url, + data=mock.ANY, headers=mock.ANY, + verify=mock.ANY, cert=mock.ANY) - def test_no_result_data(self): + @mock.patch.object(requests, 'request', return_value=FakeResponse(200)) + def test_no_result_data(self, mock_request): req = wsgi.Request.blank('/test') req.GET['Signature'] = 'test-signature' req.GET['AWSAccessKeyId'] = 'test-key-id' - - conn = httplib.HTTPConnection('/mock') - self.mox.StubOutWithMock(httplib.HTTPConnection, 'request') - self.mox.StubOutWithMock(httplib.HTTPConnection, 'getresponse') - self.mox.StubOutWithMock(httplib.HTTPConnection, 'close') - conn.request('POST', mox.IgnoreArg(), body=mox.IgnoreArg(), - headers=mox.IgnoreArg()) - resp = FakeResponse(200) - conn.getresponse().AndReturn(resp) - conn.close() - self.mox.ReplayAll() - resp = self.kauth(req) self._validate_ec2_error(resp, 400, 'AuthFailure') + mock_request.assert_called_with('POST', CONF.keystone_ec2_url, + data=mock.ANY, headers=mock.ANY, + verify=mock.ANY, cert=mock.ANY)