Fix auth prompt brokenness
We start by fixing this in the already-present OSC_Config class so OSC can move forward. This change needs to get ported down into os-client-config in the near future, maybe even soon enough to make the client library freeze this week. * Add the pw-func argument to the OSC_Config (or OpenStackConfig) __init__() * When looping through the auth options from the KSA plugin look for any that have a prompt defined and do not have a value already, so ask for one. Closes-bug: #1617384 Change-Id: Ic86d56b8a6844516292fb74513712b486fec4442
This commit is contained in:
parent
a08b62523f
commit
bec206fa0a
@ -25,6 +25,40 @@ LOG = logging.getLogger(__name__)
|
|||||||
# before auth plugins are loaded
|
# before auth plugins are loaded
|
||||||
class OSC_Config(OpenStackConfig):
|
class OSC_Config(OpenStackConfig):
|
||||||
|
|
||||||
|
# TODO(dtroyer): Once os-client-config with pw_func argument is in
|
||||||
|
# global-requirements we can remove __init()__
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
config_files=None,
|
||||||
|
vendor_files=None,
|
||||||
|
override_defaults=None,
|
||||||
|
force_ipv4=None,
|
||||||
|
envvar_prefix=None,
|
||||||
|
secure_files=None,
|
||||||
|
pw_func=None,
|
||||||
|
):
|
||||||
|
ret = super(OSC_Config, self).__init__(
|
||||||
|
config_files=config_files,
|
||||||
|
vendor_files=vendor_files,
|
||||||
|
override_defaults=override_defaults,
|
||||||
|
force_ipv4=force_ipv4,
|
||||||
|
envvar_prefix=envvar_prefix,
|
||||||
|
secure_files=secure_files,
|
||||||
|
)
|
||||||
|
|
||||||
|
# NOTE(dtroyer): This will be pushed down into os-client-config
|
||||||
|
# The default is there is no callback, the calling
|
||||||
|
# application must specify what to use, typically
|
||||||
|
# it will be osc_lib.shell.prompt_for_password()
|
||||||
|
if '_pw_callback' not in vars(self):
|
||||||
|
# Set the default if it doesn't already exist
|
||||||
|
self._pw_callback = None
|
||||||
|
if pw_func is not None:
|
||||||
|
# Set the passed in value
|
||||||
|
self._pw_callback = pw_func
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
def _auth_select_default_plugin(self, config):
|
def _auth_select_default_plugin(self, config):
|
||||||
"""Select a default plugin based on supplied arguments
|
"""Select a default plugin based on supplied arguments
|
||||||
|
|
||||||
@ -183,4 +217,13 @@ class OSC_Config(OpenStackConfig):
|
|||||||
else:
|
else:
|
||||||
config['auth'][p_opt.dest] = winning_value
|
config['auth'][p_opt.dest] = winning_value
|
||||||
|
|
||||||
|
# See if this needs a prompting
|
||||||
|
if (
|
||||||
|
'prompt' in vars(p_opt) and
|
||||||
|
p_opt.prompt is not None and
|
||||||
|
p_opt.dest not in config['auth'] and
|
||||||
|
self._pw_callback is not None
|
||||||
|
):
|
||||||
|
config['auth'][p_opt.dest] = self._pw_callback(p_opt.prompt)
|
||||||
|
|
||||||
return config
|
return config
|
||||||
|
@ -44,12 +44,10 @@ class ClientManager(clientmanager.ClientManager):
|
|||||||
self,
|
self,
|
||||||
cli_options=None,
|
cli_options=None,
|
||||||
api_version=None,
|
api_version=None,
|
||||||
pw_func=None,
|
|
||||||
):
|
):
|
||||||
super(ClientManager, self).__init__(
|
super(ClientManager, self).__init__(
|
||||||
cli_options=cli_options,
|
cli_options=cli_options,
|
||||||
api_version=api_version,
|
api_version=api_version,
|
||||||
pw_func=pw_func,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO(dtroyer): For compatibility; mark this for removal when plugin
|
# TODO(dtroyer): For compatibility; mark this for removal when plugin
|
||||||
|
@ -145,6 +145,7 @@ class OpenStackShell(shell.OpenStackShell):
|
|||||||
'interface': None,
|
'interface': None,
|
||||||
'auth_type': self._auth_type,
|
'auth_type': self._auth_type,
|
||||||
},
|
},
|
||||||
|
pw_func=shell.prompt_for_password,
|
||||||
)
|
)
|
||||||
except (IOError, OSError) as e:
|
except (IOError, OSError) as e:
|
||||||
self.log.critical("Could not read clouds.yaml configuration file")
|
self.log.critical("Could not read clouds.yaml configuration file")
|
||||||
@ -162,7 +163,6 @@ class OpenStackShell(shell.OpenStackShell):
|
|||||||
self.client_manager = clientmanager.ClientManager(
|
self.client_manager = clientmanager.ClientManager(
|
||||||
cli_options=self.cloud,
|
cli_options=self.cloud,
|
||||||
api_version=self.api_version,
|
api_version=self.api_version,
|
||||||
pw_func=shell.prompt_for_password,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -354,6 +354,64 @@ class TestShellCliV3Integ(TestShellInteg):
|
|||||||
self.assertFalse(self.requests_mock.request_history[0].verify)
|
self.assertFalse(self.requests_mock.request_history[0].verify)
|
||||||
|
|
||||||
|
|
||||||
|
class TestShellCliV3Prompt(TestShellInteg):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(TestShellCliV3Prompt, self).setUp()
|
||||||
|
env = {
|
||||||
|
"OS_AUTH_URL": V3_AUTH_URL,
|
||||||
|
"OS_PROJECT_DOMAIN_ID": test_shell.DEFAULT_PROJECT_DOMAIN_ID,
|
||||||
|
"OS_USER_DOMAIN_ID": test_shell.DEFAULT_USER_DOMAIN_ID,
|
||||||
|
"OS_USERNAME": test_shell.DEFAULT_USERNAME,
|
||||||
|
"OS_IDENTITY_API_VERSION": "3",
|
||||||
|
}
|
||||||
|
self.useFixture(osc_lib_utils.EnvFixture(copy.deepcopy(env)))
|
||||||
|
|
||||||
|
self.token = ksa_fixture.V3Token(
|
||||||
|
project_domain_id=test_shell.DEFAULT_PROJECT_DOMAIN_ID,
|
||||||
|
user_domain_id=test_shell.DEFAULT_USER_DOMAIN_ID,
|
||||||
|
user_name=test_shell.DEFAULT_USERNAME,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set up the v3 auth routes
|
||||||
|
self.requests_mock.register_uri(
|
||||||
|
'GET',
|
||||||
|
V3_AUTH_URL,
|
||||||
|
json=V3_VERSION_RESP,
|
||||||
|
status_code=200,
|
||||||
|
)
|
||||||
|
self.requests_mock.register_uri(
|
||||||
|
'POST',
|
||||||
|
V3_AUTH_URL + 'auth/tokens',
|
||||||
|
json=self.token,
|
||||||
|
status_code=200,
|
||||||
|
)
|
||||||
|
|
||||||
|
@mock.patch("osc_lib.shell.prompt_for_password")
|
||||||
|
def test_shell_callback(self, mock_prompt):
|
||||||
|
mock_prompt.return_value = "qaz"
|
||||||
|
_shell = shell.OpenStackShell()
|
||||||
|
_shell.run("configuration show".split())
|
||||||
|
|
||||||
|
# Check general calls
|
||||||
|
self.assertEqual(len(self.requests_mock.request_history), 2)
|
||||||
|
|
||||||
|
# Check password callback set correctly
|
||||||
|
self.assertEqual(
|
||||||
|
mock_prompt,
|
||||||
|
_shell.cloud._openstack_config._pw_callback
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check auth request
|
||||||
|
auth_req = self.requests_mock.request_history[1].json()
|
||||||
|
|
||||||
|
# Check returned password from prompt function
|
||||||
|
self.assertEqual(
|
||||||
|
"qaz",
|
||||||
|
auth_req['auth']['identity']['password']['user']['password'],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestShellCliPrecedence(TestShellInteg):
|
class TestShellCliPrecedence(TestShellInteg):
|
||||||
"""Validate option precedence rules without clouds.yaml
|
"""Validate option precedence rules without clouds.yaml
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user