Adds a whitelist for endpoint catalog substitution

Change-Id: If02327d70d0143d805969fe927898f08eb84c4c2
Closes-Bug: #1354208
This commit is contained in:
David Stanek 2014-08-15 11:57:07 -05:00 committed by Tristan Cacqueray
parent b31fc6da27
commit 878f12e160
4 changed files with 47 additions and 4 deletions

View File

@ -22,6 +22,7 @@ import six
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.openstack.common.gettextutils import _ from keystone.openstack.common.gettextutils import _
@ -34,6 +35,9 @@ LOG = log.getLogger(__name__)
def format_url(url, data): def format_url(url, data):
"""Safely string formats a user-defined URL with the given data.""" """Safely string formats a user-defined URL with the given data."""
data = utils.WhiteListedFormatter(
CONF.catalog.endpoint_substitution_whitelist,
data)
try: try:
result = url.replace('$(', '%(') % data result = url.replace('$(', '%(') % data
except AttributeError: except AttributeError:

View File

@ -640,7 +640,17 @@ FILE_OPTIONS = {
help='Keystone catalog backend driver.'), help='Keystone catalog backend driver.'),
cfg.IntOpt('list_limit', default=None, cfg.IntOpt('list_limit', default=None,
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='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.')],
'kvs': [ 'kvs': [
cfg.ListOpt('backends', default=[], cfg.ListOpt('backends', default=[],
help='Extra dogpile.cache backend modules to register ' help='Extra dogpile.cache backend modules to register '

View File

@ -525,3 +525,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 WhiteListedFormatter(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,13 +10,21 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import testtools
from keystone.catalog import core from keystone.catalog import core
from keystone import config
from keystone import exception from keystone import exception
from keystone import tests
class FormatUrlTests(testtools.TestCase): CONF = config.CONF
class FormatUrlTests(tests.TestCase):
def setUp(self):
super(FormatUrlTests, self).setUp()
whitelist = ['host', 'port', 'part1', 'part2']
CONF.catalog.endpoint_substitution_whitelist = whitelist
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'
@ -53,3 +61,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)