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:
Dean Troyer 2016-08-29 11:07:49 -05:00
parent a08b62523f
commit bec206fa0a
4 changed files with 102 additions and 3 deletions

View File

@ -25,6 +25,40 @@ LOG = logging.getLogger(__name__)
# before auth plugins are loaded
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):
"""Select a default plugin based on supplied arguments
@ -183,4 +217,13 @@ class OSC_Config(OpenStackConfig):
else:
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

View File

@ -44,12 +44,10 @@ class ClientManager(clientmanager.ClientManager):
self,
cli_options=None,
api_version=None,
pw_func=None,
):
super(ClientManager, self).__init__(
cli_options=cli_options,
api_version=api_version,
pw_func=pw_func,
)
# TODO(dtroyer): For compatibility; mark this for removal when plugin

View File

@ -145,6 +145,7 @@ class OpenStackShell(shell.OpenStackShell):
'interface': None,
'auth_type': self._auth_type,
},
pw_func=shell.prompt_for_password,
)
except (IOError, OSError) as e:
self.log.critical("Could not read clouds.yaml configuration file")
@ -162,7 +163,6 @@ class OpenStackShell(shell.OpenStackShell):
self.client_manager = clientmanager.ClientManager(
cli_options=self.cloud,
api_version=self.api_version,
pw_func=shell.prompt_for_password,
)

View File

@ -354,6 +354,64 @@ class TestShellCliV3Integ(TestShellInteg):
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):
"""Validate option precedence rules without clouds.yaml