From: Steve Baker Date: Mon, 19 Aug 2013 02:35:06 +0000 (+1200) Subject: Always validate auth_uri with allowed_auth_uris X-Git-Tag: 2014.1~152^2 X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=da0313cf7b1591666d76b79615b2eccc78c67ffd;p=openstack-build%2Fheat-build.git Always validate auth_uri with allowed_auth_uris The original intention was to allow heat to orchestrate on any requested cloud when allowed_auth_uris is configured with an empty list. This change makes all requests be validated against allowed_auth_uris for the following reasons: - there is a potential security issue with requests being authorised by a fake keystone, allowing an exploit in heat to be executed without any valid authentication factors first being presented. - ec2token middleware will also need to be made multi-cloud aware however as a compatible API it is not possible to specify the desired auth_uri with each request. Instead ec2token will need a list of configured endpoints so that it can try each one until a request is authenticated. Change-Id: I3d6b7edf381a66b87b6e1fae07bc5dbe9db024bc --- diff --git a/etc/heat/heat.conf.sample b/etc/heat/heat.conf.sample index 8a31cd20..b4e6872f 100644 --- a/etc/heat/heat.conf.sample +++ b/etc/heat/heat.conf.sample @@ -549,8 +549,9 @@ # Allow orchestration of multiple clouds (boolean value) #multi_cloud=false -# Allowed targets for auth_uri when multi_cloud is enabled. -# If empty, all targets will be allowed. (list value) +# Allowed keystone endpoints for auth_uri when multi_cloud is +# enabled. At least one endpoint needs to be specified. (list +# value) #allowed_auth_uris= diff --git a/heat/common/auth_password.py b/heat/common/auth_password.py index 9164710d..1ccdb2b9 100644 --- a/heat/common/auth_password.py +++ b/heat/common/auth_password.py @@ -117,8 +117,9 @@ class KeystonePasswordAuthProtocol(object): 'X-Auth-Url')) return resp(env, start_response) allowed = cfg.CONF.auth_password.allowed_auth_uris - if allowed and not auth_url in allowed: - resp = HTTPUnauthorized(_('Header X-Auth-Url "%s" not allowed') + if auth_url not in allowed: + resp = HTTPUnauthorized(_('Header X-Auth-Url "%s" not an allowed ' + 'endpoint') % auth_url) return resp(env, start_response) return None diff --git a/heat/common/config.py b/heat/common/config.py index 8feeacb3..918ae4d2 100644 --- a/heat/common/config.py +++ b/heat/common/config.py @@ -117,8 +117,9 @@ auth_password_opts = [ help=_('Allow orchestration of multiple clouds')), cfg.ListOpt('allowed_auth_uris', default=[], - help=_('Allowed targets for auth_uri when multi_cloud is ' - 'enabled. If empty, all targets will be allowed.'))] + help=_('Allowed keystone endpoints for auth_uri when ' + 'multi_cloud is enabled. At least one endpoint needs ' + 'to be specified.'))] cfg.CONF.register_opts(db_opts) cfg.CONF.register_opts(engine_opts) diff --git a/heat/tests/test_auth_password.py b/heat/tests/test_auth_password.py index 4aa15640..aba9b2b5 100644 --- a/heat/tests/test_auth_password.py +++ b/heat/tests/test_auth_password.py @@ -124,7 +124,8 @@ class KeystonePasswordAuthProtocolTest(HeatTestCase): self.middleware(req.environ, self._start_fake_response) self.assertEqual(self.response_status, 401) - def _test_multi_cloud(self, allowed_auth_uris=[]): + def test_multi_cloud(self): + allowed_auth_uris = ['http://multicloud.test.com:5000/v2.0'] cfg.CONF.set_override('multi_cloud', True, group='auth_password') auth_url = 'http://multicloud.test.com:5000/v2.0' cfg.CONF.set_override('allowed_auth_uris', @@ -147,11 +148,18 @@ class KeystonePasswordAuthProtocolTest(HeatTestCase): self.middleware(req.environ, self._start_fake_response) self.m.VerifyAll() - def test_multi_cloud(self): - self._test_multi_cloud(['http://multicloud.test.com:5000/v2.0']) - def test_multi_cloud_empty_allowed_uris(self): - self._test_multi_cloud() + cfg.CONF.set_override('multi_cloud', True, group='auth_password') + auth_url = 'http://multicloud.test.com:5000/v2.0' + cfg.CONF.set_override('allowed_auth_uris', + [], + group='auth_password') + req = webob.Request.blank('/tenant_id1/') + req.headers['X_AUTH_USER'] = 'user_name1' + req.headers['X_AUTH_KEY'] = 'goodpassword' + req.headers['X_AUTH_URL'] = auth_url + self.middleware(req.environ, self._start_fake_response) + self.assertEqual(self.response_status, 401) def test_multi_cloud_target_not_allowed(self): cfg.CONF.set_override('multi_cloud', True, group='auth_password')