replace httplib.HTTPSConnection in EC2KeystoneAuth
httplib.HTTPSConnection is known to not verify SSL certificates in Python 2.x. This change replaces use of httplib.HTTPSConnection with the requests module. It imports config settings related to SSL verification: ssl.key_file, ssl.cert_file, and ssl.ca_file. It also adds one config setting: keystone_ec2_insecure. By default, SSL verification is on, but can be disabled by setting: keystone_ec2_insecure=true This patch is based on the keystone middleware ec2 token patch: https://review.openstack.org/#/c/76476 SecurityImpact DocImpact Closes-Bug: #1373992 Change-Id: I8e46d41164e9478b820cad569ba82f25de244620
This commit is contained in:
parent
e5a231844b
commit
cff14b3763
|
@ -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']
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue