Fix murano_auth usage

Use the OpenStack standard keystoneauth1 library for loading
authentication plugins and register their options in the
murano_auth section.
Still provide a fallback if no murano_auth.auth_type is specified
to make old config files work.

Closes-bug: 1705838
Change-Id: Ie74364a4401f64fe42bf2206b6df760d2fc60edb
This commit is contained in:
Gyorgy Szombathelyi 2017-07-21 12:52:06 +02:00
parent 4a50a623c4
commit 25317e3801
5 changed files with 152 additions and 133 deletions

View File

@ -188,12 +188,8 @@ function configure_murano {
configure_auth_token_middleware $MURANO_CONF_FILE $MURANO_ADMIN_USER $MURANO_AUTH_CACHE_DIR
# Setup murano_auth section
configure_auth_token_middleware $MURANO_CONF_FILE $MURANO_ADMIN_USER $MURANO_AUTH_CACHE_DIR murano_auth
iniset $MURANO_CONF_FILE murano_auth auth_uri $KEYSTONE_AUTH_URI
iniset $MURANO_CONF_FILE murano_auth admin_project_name $SERVICE_TENANT_NAME
iniset $MURANO_CONF_FILE murano_auth admin_user $MURANO_ADMIN_USER
iniset $MURANO_CONF_FILE murano_auth admin_password $SERVICE_PASSWORD
iniset $MURANO_CONF_FILE murano_auth user_domain_name "$SERVICE_DOMAIN_NAME"
iniset $MURANO_CONF_FILE murano_auth project_domain_name "$SERVICE_DOMAIN_NAME"
configure_murano_rpc_backend

View File

@ -23,42 +23,35 @@ from murano.dsl import helpers
CFG_KEYSTONE_GROUP = 'keystone_authtoken'
CFG_MURANO_AUTH_GROUP = 'murano_auth'
LOG = logging.getLogger(__name__)
cfg.CONF.import_group(CFG_KEYSTONE_GROUP, 'keystonemiddleware.auth_token')
def _get_keystone_auth(trust_id=None):
auth_uri = cfg.CONF['murano_auth'].auth_uri
username = cfg.CONF['murano_auth'].admin_user
password = cfg.CONF['murano_auth'].admin_password
user_domain_name = cfg.CONF['murano_auth'].user_domain_name or "default"
auth_type = cfg.CONF['murano_auth'].auth_type
project_name = cfg.CONF['murano_auth'].admin_project_name
project_domain_name = cfg.CONF['murano_auth'].project_domain_name or \
"default"
if not (auth_uri and username and password):
versionutils.report_deprecated_feature(
LOG, "Please update configuration in 'murano_auth' group")
auth_uri = cfg.CONF[CFG_KEYSTONE_GROUP].auth_uri
username = cfg.CONF[CFG_KEYSTONE_GROUP].admin_user
password = cfg.CONF[CFG_KEYSTONE_GROUP].admin_password
auth_type = cfg.CONF[CFG_KEYSTONE_GROUP].auth_type
project_name = cfg.CONF[CFG_KEYSTONE_GROUP].admin_tenant_name
if not auth_type:
# Fallback to legacy v2 options if no auth_type is set.
if not cfg.CONF[CFG_MURANO_AUTH_GROUP].auth_type:
# Fallback to legacy v2 options in keystone_authtoken
# if no auth_type is set.
# If auth_type is set, it is possible to use the auth loader
# from keystoneauth1. This is the same fallback as keystonemiddleware
# uses.
versionutils.report_deprecated_feature(
LOG, 'Please update configuration in ' + CFG_MURANO_AUTH_GROUP +
' group')
auth_uri = cfg.CONF[CFG_KEYSTONE_GROUP].auth_uri
username = cfg.CONF[CFG_KEYSTONE_GROUP].admin_user
password = cfg.CONF[CFG_KEYSTONE_GROUP].admin_password
project_name = cfg.CONF[CFG_KEYSTONE_GROUP].admin_tenant_name
kwargs = {
'auth_url': auth_uri.replace('v2.0', 'v3'),
'username': username,
'password': password,
'user_domain_name': user_domain_name
'user_domain_name': 'default'
}
if not trust_id:
kwargs['project_name'] = project_name
kwargs['project_domain_name'] = project_domain_name
kwargs['project_domain_name'] = 'default'
else:
kwargs['trust_id'] = trust_id
auth = identity.Password(**kwargs)
@ -73,16 +66,14 @@ def _get_keystone_auth(trust_id=None):
kwargs['trust_id'] = trust_id
auth = ka_loading.load_auth_from_conf_options(
cfg.CONF,
CFG_KEYSTONE_GROUP,
CFG_MURANO_AUTH_GROUP,
**kwargs)
return auth
def _create_keystone_admin_client():
auth = _get_keystone_auth()
session = _get_session(
auth=auth,
conf_section=cfg.CONF[CFG_KEYSTONE_GROUP])
session = _get_session(auth=auth)
return ks_client.Client(session=session)
@ -100,10 +91,11 @@ def get_client_session(execution_session=None, conf=None):
def get_token_client_session(token=None, project_id=None, conf=None):
auth_uri = cfg.CONF['murano_auth'].auth_uri
auth_uri = cfg.CONF[CFG_MURANO_AUTH_GROUP].auth_uri
if not auth_uri:
versionutils.report_deprecated_feature(
LOG, "Please update configuration in 'murano_auth' group")
LOG, 'Please configure auth_uri in ' + CFG_MURANO_AUTH_GROUP +
' group')
auth_uri = cfg.CONF[CFG_KEYSTONE_GROUP].auth_uri
auth_url = auth_uri.replace('v2.0', 'v3')
if token is None or project_id is None:
@ -155,11 +147,11 @@ def _get_config_option(conf_section, option_names, default=None):
return default
def _get_session(auth, conf_section):
# Fallback to keystone_authtoken section for TLS parameters
def _get_session(auth, conf_section=None):
# Fallback to murano_auth section for TLS parameters
# if no other conf_section supplied
if not conf_section:
conf_section = cfg.CONF[CFG_KEYSTONE_GROUP]
conf_section = cfg.CONF[CFG_MURANO_AUTH_GROUP]
session = ka_loading.session.Session().load_from_options(
auth=auth,
insecure=_get_config_option(conf_section, 'insecure', False),

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from keystoneauth1 import loading as ks_loading
from oslo_config import cfg
from oslo_log import log as logging
from oslo_middleware import cors
@ -332,26 +333,11 @@ home_region = cfg.StrOpt(
'home_region',
help="Default region name used to get services endpoints.")
# Unfortuntely we cannot use murano_auth.auth_url, since it
# is private to the actual authentication plugin used.
murano_auth_opts = [
cfg.StrOpt('auth_type', help='Authentication type to load.'),
cfg.StrOpt('auth_uri', help='Identity API endpoint.'),
cfg.StrOpt('admin_user',
help='User name for murano authentication.'),
cfg.StrOpt('admin_password', secret=True,
help='Password for murano authentication.'),
cfg.StrOpt('user_domain_name',
help="User's domain name for authentication."),
cfg.StrOpt('admin_project_name',
help="Project name for project scoping."),
cfg.StrOpt('project_domain_name',
help="Project's domain name."),
]
cfg.StrOpt('auth_uri',
help='Identity API endpoint for authenticating with tokens.')]
CONF = cfg.CONF
@ -371,6 +357,8 @@ CONF.register_opts(networking_opts, group='networking')
CONF.register_opts(glare_opts, group='glare')
CONF.register_opts(glance_opts, group='glance')
CONF.register_opts(murano_auth_opts, group='murano_auth')
ks_loading.register_auth_conf_options(CONF, group='murano_auth')
ks_loading.register_session_conf_options(CONF, group='murano_auth')
def parse_args(args=None, usage=None, default_config_files=None):

View File

@ -19,6 +19,7 @@ __all__ = [
import copy
import itertools
from keystoneauth1 import loading as ks_loading
import oslo_service.sslutils
@ -43,7 +44,13 @@ _opt_lists = [
('mistral', murano.common.config.mistral_opts),
('networking', murano.common.config.networking_opts),
('stats', murano.common.config.stats_opts),
('murano_auth', murano.common.config.murano_auth_opts),
('murano_auth',
murano.common.config.murano_auth_opts +
ks_loading.get_session_conf_options() +
ks_loading.get_auth_common_conf_options() +
ks_loading.get_auth_plugin_conf_options('password') +
ks_loading.get_auth_plugin_conf_options('v2password') +
ks_loading.get_auth_plugin_conf_options('v3password')),
(None, build_list([
murano.common.config.metadata_dir,
murano.common.config.bind_opts,

View File

@ -20,11 +20,22 @@ from keystoneauth1 import loading as ka_loading
from murano.common import auth_utils
from murano.tests.unit import base
from oslo_config import cfg
class TestAuthUtils(base.MuranoTestCase):
def setUp(self):
super(TestAuthUtils, self).setUp()
# Register the Password auth plugin options,
# so we can use CONF.set_override
password_option = ka_loading.get_auth_plugin_conf_options('password')
cfg.CONF.register_opts(password_option,
group=auth_utils.CFG_MURANO_AUTH_GROUP)
self.addCleanup(
cfg.CONF.unregister_opts,
password_option,
group=auth_utils.CFG_MURANO_AUTH_GROUP)
self.addCleanup(mock.patch.stopall)
def _init_mock_cfg(self, auth_type):
@ -33,33 +44,73 @@ class TestAuthUtils(base.MuranoTestCase):
spec_set=ka_loading).start()
mock_auth_obj.load_auth_from_conf_options.return_value = \
mock.sentinel.auth
mock_auth_obj.session.Session.return_value.load_from_options.\
mock_auth_obj.session.Session().load_from_options.\
return_value = mock.sentinel.session
cfg.CONF.set_override('auth_type',
'password',
auth_utils.CFG_MURANO_AUTH_GROUP)
cfg.CONF.set_override('auth_uri',
'foo_auth_uri',
auth_utils.CFG_MURANO_AUTH_GROUP)
cfg.CONF.set_override('auth_url',
'foo_auth_url',
auth_utils.CFG_MURANO_AUTH_GROUP)
cfg.CONF.set_override('username',
'fakeuser',
auth_utils.CFG_MURANO_AUTH_GROUP)
cfg.CONF.set_override('password',
'fakepass',
auth_utils.CFG_MURANO_AUTH_GROUP)
cfg.CONF.set_override('user_domain_name',
'Default',
auth_utils.CFG_MURANO_AUTH_GROUP)
cfg.CONF.set_override('project_domain_name',
'Default',
auth_utils.CFG_MURANO_AUTH_GROUP)
cfg.CONF.set_override('project_name',
'fakeproj',
auth_utils.CFG_MURANO_AUTH_GROUP)
else:
mock_auth_obj = mock.patch.object(auth_utils, 'identity',
autospec=True).start()
mock_auth_obj.Password.return_value = mock.sentinel.auth
mock_cfg = mock.patch.object(auth_utils, 'cfg', autospec=True).start()
mock_conf = mock_cfg.CONF.__getitem__.return_value
mock_conf.auth_type = auth_type
mock_conf.auth_uri = 'foo_auth_uri/v2.0'
mock_conf.admin_user = mock.sentinel.admin_user
mock_conf.admin_password = mock.sentinel.admin_password
mock_conf.admin_project_name = mock.sentinel.admin_project_name
mock_conf.user_domain_name = mock.sentinel.user_domain_name
mock_conf.project_domain_name = mock.sentinel.project_domain_name
return mock_cfg, mock_auth_obj
cfg.CONF.set_override('auth_type',
None,
auth_utils.CFG_MURANO_AUTH_GROUP)
cfg.CONF.set_override('auth_uri',
'foo_auth_uri/v3',
auth_utils.CFG_KEYSTONE_GROUP)
cfg.CONF.set_override('admin_user',
'adminuser',
auth_utils.CFG_KEYSTONE_GROUP)
cfg.CONF.set_override('admin_password',
'adminpass',
auth_utils.CFG_KEYSTONE_GROUP)
cfg.CONF.set_override('admin_tenant_name',
'admintenant',
auth_utils.CFG_KEYSTONE_GROUP)
return mock_auth_obj
def test_get_keystone_auth(self):
mock_cfg, mock_identity = self._init_mock_cfg(False)
mock_identity = self._init_mock_cfg(True)
expected_auth = mock.sentinel.auth
actual_auth = auth_utils._get_keystone_auth()
self.assertEqual(expected_auth, actual_auth)
mock_identity.load_auth_from_conf_options.assert_called_once_with(
cfg.CONF, auth_utils.CFG_MURANO_AUTH_GROUP)
def test_get_keystone_auth_fallback_to_v2(self):
mock_identity = self._init_mock_cfg(False)
expected_kwargs = {
'auth_url': 'foo_auth_uri/v3',
'username': mock.sentinel.admin_user,
'password': mock.sentinel.admin_password,
'user_domain_name': mock.sentinel.user_domain_name,
'project_name': mock.sentinel.admin_project_name,
'project_domain_name': mock.sentinel.project_domain_name
'username': 'adminuser',
'password': 'adminpass',
'user_domain_name': 'default',
'project_name': 'admintenant',
'project_domain_name': 'default'
}
expected_auth = mock.sentinel.auth
actual_auth = auth_utils._get_keystone_auth()
@ -67,24 +118,8 @@ class TestAuthUtils(base.MuranoTestCase):
self.assertEqual(expected_auth, actual_auth)
mock_identity.Password.assert_called_once_with(**expected_kwargs)
def test_get_keystone_auth_with_trust_id(self):
mock_cfg, mock_identity = self._init_mock_cfg(False)
expected_kwargs = {
'auth_url': 'foo_auth_uri/v3',
'username': mock.sentinel.admin_user,
'password': mock.sentinel.admin_password,
'user_domain_name': mock.sentinel.user_domain_name,
'trust_id': mock.sentinel.trust_id
}
expected_auth = mock.sentinel.auth
actual_auth = auth_utils._get_keystone_auth(mock.sentinel.trust_id)
self.assertEqual(expected_auth, actual_auth)
mock_identity.Password.assert_called_once_with(**expected_kwargs)
def test_get_keystone_auth_without_auth(self):
mock_cfg, mock_ka_loading = self._init_mock_cfg(True)
def test_get_keystone_with_trust_id(self):
mock_ka_loading = self._init_mock_cfg(True)
expected_kwargs = {
'project_name': None,
@ -97,10 +132,26 @@ class TestAuthUtils(base.MuranoTestCase):
self.assertEqual(expected_auth, actual_auth)
mock_ka_loading.load_auth_from_conf_options.assert_called_once_with(
mock_cfg.CONF,
auth_utils.CFG_KEYSTONE_GROUP,
cfg.CONF,
auth_utils.CFG_MURANO_AUTH_GROUP,
**expected_kwargs)
def test_get_keystone_auth_with_trust_id_fallback_to_v2(self):
mock_identity = self._init_mock_cfg(False)
expected_kwargs = {
'auth_url': 'foo_auth_uri/v3',
'username': 'adminuser',
'password': 'adminpass',
'user_domain_name': 'default',
'trust_id': mock.sentinel.trust_id
}
expected_auth = mock.sentinel.auth
actual_auth = auth_utils._get_keystone_auth(mock.sentinel.trust_id)
self.assertEqual(expected_auth, actual_auth)
mock_identity.Password.assert_called_once_with(**expected_kwargs)
@mock.patch.object(auth_utils, 'ks_client', autospec=True)
@mock.patch.object(auth_utils, '_get_session', autospec=True)
def test_create_keystone_admin_client(self, mock_get_sess, mock_ks_client):
@ -132,7 +183,8 @@ class TestAuthUtils(base.MuranoTestCase):
mock_get_execution_session.assert_called_once_with()
mock_get_keystone_auth.assert_called_once_with(mock.sentinel.trust_id)
mock_get_session.assert_called_once_with(
auth=mock.sentinel.auth, conf_section=mock.sentinel.conf)
auth=mock.sentinel.auth,
conf_section=mock.sentinel.conf)
@mock.patch.object(auth_utils, 'get_token_client_session', autospec=True)
@mock.patch.object(
@ -156,18 +208,20 @@ class TestAuthUtils(base.MuranoTestCase):
@mock.patch.object(auth_utils, 'identity', autospec=True)
@mock.patch.object(
auth_utils.helpers, 'get_execution_session', autospec=True)
@mock.patch.object(auth_utils, 'cfg', autospec=True)
def test_get_token_client_session(
self, mock_cfg, mock_get_execution_session, mock_identity,
self, mock_get_execution_session, mock_identity,
mock_get_session):
mock_cfg.CONF.__getitem__.return_value.auth_uri = 'foo_auth_uri/v2.0'
cfg.CONF.set_override('auth_uri',
'foo_auth_uri/v2.0',
auth_utils.CFG_MURANO_AUTH_GROUP)
mock_get_execution_session.return_value = \
mock.Mock(token=mock.sentinel.token,
project_id=mock.sentinel.project_id)
mock_identity.Token.return_value = mock.sentinel.auth
mock_get_session.return_value = mock.sentinel.session
session = auth_utils.get_token_client_session(conf=mock.sentinel.conf)
session = auth_utils.get_token_client_session()
self.assertEqual(mock.sentinel.session, session)
mock_get_execution_session.assert_called_once_with()
@ -175,7 +229,8 @@ class TestAuthUtils(base.MuranoTestCase):
'foo_auth_uri/v3', token=mock.sentinel.token,
project_id=mock.sentinel.project_id)
mock_get_session.assert_called_once_with(
auth=mock.sentinel.auth, conf_section=mock.sentinel.conf)
auth=mock.sentinel.auth,
conf_section=None)
@mock.patch.object(auth_utils, 'get_token_client_session', autospec=True)
@mock.patch.object(auth_utils, 'ks_client', autospec=True)
@ -256,43 +311,30 @@ class TestAuthUtils(base.MuranoTestCase):
def test_get_config_option_return_default(self):
self.assertIsNone(auth_utils._get_config_option(None, []))
@mock.patch.object(auth_utils, '_get_config_option', autospec=True)
def test_get_session(self, mock_get_config_option):
mock_cfg, mock_ka_loading = self._init_mock_cfg(True)
mock_cfg.CONF.__getitem__.return_value = mock.sentinel.conf_section
mock_get_config_option.side_effect = [
mock.sentinel.secure_option,
mock.sentinel.cacert_option,
mock.sentinel.keyfile_option,
mock.sentinel.cert_option,
]
def test_get_session(self):
mock_ka_loading = self._init_mock_cfg(True)
session = auth_utils._get_session(mock.sentinel.auth, None)
session = auth_utils._get_session(mock.sentinel.auth)
self.assertEqual(mock.sentinel.session, session)
mock_ka_loading.session.Session.return_value.load_from_options.\
mock_ka_loading.session.Session().load_from_options.\
assert_called_once_with(auth=mock.sentinel.auth,
insecure=mock.sentinel.secure_option,
cacert=mock.sentinel.cacert_option,
key=mock.sentinel.keyfile_option,
cert=mock.sentinel.cert_option)
cacert=None,
cert=None,
insecure=False,
key=None)
@mock.patch.object(auth_utils, '_get_config_option', autospec=True)
@mock.patch.object(auth_utils, 'cfg', autospec=True)
def test_get_session_client_parameters(
self, mock_cfg, mock_get_config_option):
mock_cfg.CONF.home_region = mock.sentinel.home_region
mock_get_config_option.side_effect = [
mock.sentinel.url,
mock.sentinel.endpoint_type
]
def test_get_session_client_parameters(self):
cfg.CONF.set_override('url', 'foourl', 'murano')
expected_result = {
'session': mock.sentinel.session,
'endpoint_override': mock.sentinel.url
'endpoint_override': 'foourl'
}
result = auth_utils.get_session_client_parameters(
conf=cfg.CONF.murano,
service_type=mock.sentinel.service_type,
service_name=mock.sentinel.service_name,
session=mock.sentinel.session)
@ -300,27 +342,21 @@ class TestAuthUtils(base.MuranoTestCase):
for key, val in expected_result.items():
self.assertEqual(val, result[key])
@mock.patch.object(auth_utils, '_get_config_option', autospec=True)
@mock.patch.object(auth_utils, 'cfg', autospec=True)
def test_get_session_client_parameters_without_url(
self, mock_cfg, mock_get_config_option):
mock_cfg.CONF.home_region = mock.sentinel.home_region
mock_get_config_option.side_effect = [
None,
mock.sentinel.endpoint_type
]
def test_get_session_client_parameters_without_url(self):
cfg.CONF.set_override('home_region', 'fooregion')
expected_result = {
'session': mock.sentinel.session,
'service_type': mock.sentinel.service_type,
'service_name': mock.sentinel.service_name,
'interface': mock.sentinel.endpoint_type,
'region_name': mock.sentinel.home_region
'region_name': 'fooregion'
}
result = auth_utils.get_session_client_parameters(
service_type=mock.sentinel.service_type,
service_name=mock.sentinel.service_name,
interface=mock.sentinel.endpoint_type,
session=mock.sentinel.session)
for key, val in expected_result.items():