diff --git a/heat/api/aws/ec2token.py b/heat/api/aws/ec2token.py index 038f0dced..825b02ba4 100644 --- a/heat/api/aws/ec2token.py +++ b/heat/api/aws/ec2token.py @@ -39,7 +39,21 @@ opts = [ default=[], help=_('Allowed keystone endpoints for auth_uri when ' 'multi_cloud is enabled. At least one endpoint needs ' - 'to be specified.')) + 'to be specified.')), + cfg.StrOpt('cert_file', + default=None, + help=_('Optional PEM-formatted certificate chain file.')), + cfg.StrOpt('key_file', + default=None, + help=_('Optional PEM-formatted file that contains the ' + 'private key.')), + cfg.StrOpt('ca_file', + default=None, + help=_('Optional CA cert file to use in SSL connections.')), + cfg.BoolOpt('insecure', + default=False, + help=_('If set, then the server\'s certificate will not ' + 'be verified.')), ] cfg.CONF.register_opts(opts, group='ec2authtoken') @@ -50,6 +64,7 @@ class EC2Token(wsgi.Middleware): def __init__(self, app, conf): self.conf = conf self.application = app + self._ssl_options = None def _conf_get(self, name): # try config from paste-deploy first @@ -131,6 +146,19 @@ class EC2Token(wsgi.Middleware): last_failure = e raise last_failure or exception.HeatAccessDeniedError() + @property + def ssl_options(self): + if not self._ssl_options: + cacert = self._conf_get('ca_file') + insecure = self._conf_get('insecure') + cert = self._conf_get('cert_file') + key = self._conf_get('key_file') + self._ssl_options = { + 'verify': cacert if cacert else not insecure, + 'cert': (cert, key) if cert else None + } + return self._ssl_options + def _authorize(self, req, auth_uri): # Read request signature and access id. # If we find X-Auth-User in the headers we ignore a key error @@ -185,7 +213,9 @@ class EC2Token(wsgi.Middleware): keystone_ec2_uri = self._conf_get_keystone_ec2_uri(auth_uri) LOG.info(_LI('Authenticating with %s'), keystone_ec2_uri) response = requests.post(keystone_ec2_uri, data=creds_json, - headers=headers) + headers=headers, + verify=self.ssl_options['verify'], + cert=self.ssl_options['cert']) result = response.json() try: token_id = result['access']['token']['id'] diff --git a/heat/tests/test_api_ec2token.py b/heat/tests/test_api_ec2token.py index 5221480d4..006dc1f92 100644 --- a/heat/tests/test_api_ec2token.py +++ b/heat/tests/test_api_ec2token.py @@ -60,6 +60,34 @@ class Ec2TokenTest(common.HeatTestCase): 'http://192.0.2.9/v2.0/ec2tokens', ec2._conf_get_keystone_ec2_uri('http://192.0.2.9/v2.0/')) + def test_conf_get_ssl_default_options(self): + ec2 = ec2token.EC2Token(app=None, conf={}) + self.assertTrue(ec2.ssl_options['verify'], + "SSL verify should be True by default") + self.assertIsNone(ec2.ssl_options['cert'], + "SSL client cert should be None by default") + + def test_conf_ssl_insecure_option(self): + ec2 = ec2token.EC2Token(app=None, conf={}) + cfg.CONF.set_default('insecure', 'True', group='ec2authtoken') + cfg.CONF.set_default('ca_file', None, group='ec2authtoken') + self.assertFalse(ec2.ssl_options['verify']) + + def test_conf_get_ssl_opts(self): + cfg.CONF.set_default('auth_uri', 'https://192.0.2.9/v2.0/', + group='ec2authtoken') + cfg.CONF.set_default('ca_file', '/home/user/cacert.pem', + group='ec2authtoken') + cfg.CONF.set_default('insecure', 'false', group='ec2authtoken') + cfg.CONF.set_default('cert_file', '/home/user/mycert', + group='ec2authtoken') + cfg.CONF.set_default('key_file', '/home/user/mykey', + group='ec2authtoken') + ec2 = ec2token.EC2Token(app=None, conf={}) + self.assertEqual('/home/user/cacert.pem', ec2.ssl_options['verify']) + self.assertEqual(('/home/user/mycert', '/home/user/mykey'), + ec2.ssl_options['cert']) + def test_get_signature_param_old(self): params = {'Signature': 'foo'} dummy_req = self._dummy_GET_request(params) @@ -183,7 +211,8 @@ class Ec2TokenTest(common.HeatTestCase): self.assertEqual('xyz', ec2.__call__(dummy_req)) def _stub_http_connection(self, headers=None, params=None, response=None, - req_url='http://123:5000/v2.0/ec2tokens'): + req_url='http://123:5000/v2.0/ec2tokens', + verify=True, cert=None): headers = headers or {} params = params or {} @@ -206,7 +235,7 @@ class Ec2TokenTest(common.HeatTestCase): "path": "/v1", "body_hash": body_hash}}) req_headers = {'Content-Type': 'application/json'} - requests.post(req_url, data=req_creds, + requests.post(req_url, data=req_creds, verify=verify, cert=cert, headers=req_headers).AndReturn(DummyHTTPResponse()) def test_call_ok(self):