Adds a whitelist for endpoint catalog substitution

Change-Id: If02327d70d0143d805969fe927898f08eb84c4c2
Closes-Bug: #1354208
This commit is contained in:
David Stanek 2014-08-15 14:59:48 +00:00 committed by Tristan Cacqueray
parent 9d4e22b497
commit 2989ff257e
5 changed files with 55 additions and 0 deletions

View File

@ -555,6 +555,13 @@
# catalog collection. (integer value) # catalog collection. (integer value)
#list_limit=<None> #list_limit=<None>
# (Deprecated) List of possible substitutions for use in
# formatting endpoints. Use caution when modifying this list.
# It will give users with permission to create endpoints the
# ability to see those values in your configuration file. This
# option will be removed in Juno. (list value)
#endpoint_substitution_whitelist=tenant_id,user_id,public_bind_host,admin_bind_host,compute_host,compute_port,admin_port,public_port,public_endpoint,admin_endpoint
[credential] [credential]

View File

@ -23,6 +23,7 @@ from keystone.common import cache
from keystone.common import dependency from keystone.common import dependency
from keystone.common import driver_hints from keystone.common import driver_hints
from keystone.common import manager from keystone.common import manager
from keystone.common import utils
from keystone import config from keystone import config
from keystone import exception from keystone import exception
from keystone.i18n import _ from keystone.i18n import _
@ -46,6 +47,9 @@ def format_url(url, substitutions):
:returns: a formatted URL :returns: a formatted URL
""" """
substitutions = utils.WhiteListedItemFilter(
CONF.catalog.endpoint_substitution_whitelist,
substitutions)
try: try:
result = url.replace('$(', '%(') % substitutions result = url.replace('$(', '%(') % substitutions
except AttributeError: except AttributeError:

View File

@ -792,6 +792,17 @@ FILE_OPTIONS = {
cfg.IntOpt('list_limit', cfg.IntOpt('list_limit',
help='Maximum number of entities that will be returned ' help='Maximum number of entities that will be returned '
'in a catalog collection.'), 'in a catalog collection.'),
cfg.ListOpt('endpoint_substitution_whitelist',
default=['tenant_id', 'user_id', 'public_bind_host',
'admin_bind_host', 'compute_host', 'compute_port',
'admin_port', 'public_port', 'public_endpoint',
'admin_endpoint'],
help='(Deprecated) List of possible substitutions for use '
'in formatting endpoints. Use caution when modifying '
'this list. It will give users with permission to '
'create endpoints the ability to see those values '
'in your configuration file. This option will be '
'removed in Juno.'),
], ],
'kvs': [ 'kvs': [
cfg.ListOpt('backends', default=[], cfg.ListOpt('backends', default=[],

View File

@ -526,3 +526,15 @@ def make_dirs(path, mode=None, user=None, group=None, log=None):
raise EnvironmentError("makedirs('%s'): %s" % (path, exc.strerror)) raise EnvironmentError("makedirs('%s'): %s" % (path, exc.strerror))
set_permissions(path, mode, user, group, log) set_permissions(path, mode, user, group, log)
class WhiteListedItemFilter(object):
def __init__(self, whitelist, data):
self._whitelist = set(whitelist or [])
self._data = data
def __getitem__(self, name):
if name not in self._whitelist:
raise KeyError
return self._data[name]

View File

@ -10,14 +10,26 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from oslo.config import fixture as config_fixture
import testtools import testtools
from keystone.catalog import core from keystone.catalog import core
from keystone import config
from keystone import exception from keystone import exception
CONF = config.CONF
class FormatUrlTests(testtools.TestCase): class FormatUrlTests(testtools.TestCase):
def setUp(self):
super(FormatUrlTests, self).setUp()
fixture = self.useFixture(config_fixture.Config(CONF))
fixture.config(
group='catalog',
endpoint_substitution_whitelist=['host', 'port', 'part1', 'part2'])
def test_successful_formatting(self): def test_successful_formatting(self):
url_template = 'http://%(host)s:%(port)d/%(part1)s/%(part2)s' url_template = 'http://%(host)s:%(port)d/%(part1)s/%(part2)s'
values = {'host': 'server', 'port': 9090, 'part1': 'A', 'part2': 'B'} values = {'host': 'server', 'port': 9090, 'part1': 'A', 'part2': 'B'}
@ -53,3 +65,12 @@ class FormatUrlTests(testtools.TestCase):
_test(None) _test(None)
_test(object()) _test(object())
def test_substitution_with_key_not_whitelisted(self):
url_template = 'http://%(host)s:%(port)d/%(part1)s/%(part2)s/%(part3)s'
values = {'host': 'server', 'port': 9090,
'part1': 'A', 'part2': 'B', 'part3': 'C'}
self.assertRaises(exception.MalformedEndpoint,
core.format_url,
url_template,
values)