From 9cfe4b6735c4f591f36a9d0ef86d3bb33963ec19 Mon Sep 17 00:00:00 2001 From: Takashi Kajinami Date: Mon, 22 Apr 2024 14:17:42 +0900 Subject: [PATCH] Validate URI/URL options by URI type oslo.config provides the native URI type to ensure the given value is in a valid URI format. Use the feature to detect malformed values early. Change-Id: If1d76d29c3b721957b5b67b34ca700c5da2066f7 --- heat/api/aws/ec2token.py | 5 ++++- heat/common/config.py | 20 ++++++++++++-------- heat/engine/clients/os/heat_plugin.py | 4 ++-- heat/tests/api/aws/test_api_ec2token.py | 2 +- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/heat/api/aws/ec2token.py b/heat/api/aws/ec2token.py index 39b240f5aa..5854c4d47d 100644 --- a/heat/api/aws/ec2token.py +++ b/heat/api/aws/ec2token.py @@ -14,6 +14,7 @@ import hashlib from oslo_config import cfg +from oslo_config import types from oslo_log import log as logging from oslo_serialization import jsonutils as json import requests @@ -28,13 +29,15 @@ LOG = logging.getLogger(__name__) opts = [ - cfg.StrOpt('auth_uri', + cfg.URIOpt('auth_uri', + schemes=['http', 'https'], help=_("Authentication Endpoint URI.")), cfg.BoolOpt('multi_cloud', default=False, help=_('Allow orchestration of multiple clouds.')), cfg.ListOpt('allowed_auth_uris', default=[], + item_type=types.URI(schemes=['http', 'https']), help=_('Allowed keystone endpoints for auth_uri when ' 'multi_cloud is enabled. At least one endpoint needs ' 'to be specified.')), diff --git a/heat/common/config.py b/heat/common/config.py index c6a1dfcfe4..34a506508c 100644 --- a/heat/common/config.py +++ b/heat/common/config.py @@ -40,12 +40,14 @@ service_opts = [ cfg.IntOpt('periodic_interval', default=60, help=_('Seconds between running periodic tasks.')), - cfg.StrOpt('heat_metadata_server_url', + cfg.URIOpt('heat_metadata_server_url', + schemes=['http', 'https'], help=_('URL of the Heat metadata server. ' 'NOTE: Setting this is only needed if you require ' 'instances to use a different endpoint than in the ' 'keystone catalog')), - cfg.StrOpt('heat_waitcondition_server_url', + cfg.URIOpt('heat_waitcondition_server_url', + schemes=['http', 'https'], help=_('URL of the Heat waitcondition server.')), cfg.StrOpt('instance_connection_is_secure', default="0", @@ -380,14 +382,14 @@ clients_opts = [ "be verified."))] heat_client_opts = [ - cfg.StrOpt('url', - default='', + cfg.URIOpt('url', + schemes=['http', 'https'], help=_('Optional heat url in format like' ' http://0.0.0.0:8004/v1/%(tenant_id)s.'))] keystone_client_opts = [ - cfg.StrOpt('auth_uri', - default='', + cfg.URIOpt('auth_uri', + schemes=['http', 'https'], help=_('Unversioned keystone url in format like' ' http://0.0.0.0:5000.'))] @@ -544,7 +546,7 @@ def load_paste_app(app_name=None): 'e': e}) -def get_client_option(client, option): +def get_client_option(client, option, fallback=True): # look for the option in the [clients_${client}] section # unknown options raise cfg.NoSuchOptError try: @@ -552,9 +554,11 @@ def get_client_option(client, option): cfg.CONF.import_opt(option, 'heat.common.config', group=group_name) v = getattr(getattr(cfg.CONF, group_name), option) - if v is not None: + if not fallback or v is not None: return v except cfg.NoSuchGroupError: + if not fallback: + raise pass # do not error if the client is unknown # look for the option in the generic [clients] section cfg.CONF.import_opt(option, 'heat.common.config', group='clients') diff --git a/heat/engine/clients/os/heat_plugin.py b/heat/engine/clients/os/heat_plugin.py index 76cdf990d4..a406531d99 100644 --- a/heat/engine/clients/os/heat_plugin.py +++ b/heat/engine/clients/os/heat_plugin.py @@ -31,7 +31,7 @@ class HeatClientPlugin(client_plugin.ClientPlugin): def _create(self): endpoint = self.get_heat_url() args = {} - if self._get_client_option(CLIENT_NAME, 'url'): + if self._get_client_option(CLIENT_NAME, 'url', fallback=False): # assume that the heat API URL is manually configured because # it is not in the keystone catalog, so include the credentials # for the standalone auth_password middleware @@ -53,7 +53,7 @@ class HeatClientPlugin(client_plugin.ClientPlugin): return isinstance(ex, exc.HTTPConflict) def get_heat_url(self): - heat_url = self._get_client_option(CLIENT_NAME, 'url') + heat_url = self._get_client_option(CLIENT_NAME, 'url', fallback=False) if heat_url: tenant_id = self.context.tenant_id heat_url = heat_url % {'tenant_id': tenant_id} diff --git a/heat/tests/api/aws/test_api_ec2token.py b/heat/tests/api/aws/test_api_ec2token.py index af1305f609..36f79c244a 100644 --- a/heat/tests/api/aws/test_api_ec2token.py +++ b/heat/tests/api/aws/test_api_ec2token.py @@ -53,7 +53,7 @@ class Ec2TokenTest(common.HeatTestCase): def test_conf_get_opts(self): cfg.CONF.set_default('auth_uri', 'http://192.0.2.9/v2.0/', group='ec2authtoken') - cfg.CONF.set_default('auth_uri', 'this-should-be-ignored', + cfg.CONF.set_default('auth_uri', 'http://this-should-be-ignored/', group='clients_keystone') ec2 = ec2token.EC2Token(app=None, conf={}) self.assertEqual('http://192.0.2.9/v2.0/', ec2._conf_get('auth_uri'))