Prompt for password on CLI if not provided
load_from_argparse_arguments is very specifically for use with argparse. We can therefore safely prompt for a password from the user if none is provided and it won't affect config options or other loading mechanisms. Change-Id: Ib76743b768c5f0eef756184f1da49613423298f0
This commit is contained in:
parent
39b7f963f5
commit
17d51f771e
|
@ -82,3 +82,11 @@ class Password(base.BaseGenericPlugin):
|
|||
options = super(Password, cls).get_options()
|
||||
options.extend(get_options())
|
||||
return options
|
||||
|
||||
@classmethod
|
||||
def load_from_argparse_arguments(cls, namespace, **kwargs):
|
||||
if not (kwargs.get('password') or namespace.os_password):
|
||||
kwargs['password'] = utils.prompt_user_password()
|
||||
|
||||
return super(Password, cls).load_from_argparse_arguments(namespace,
|
||||
**kwargs)
|
||||
|
|
|
@ -144,6 +144,14 @@ class Password(Auth):
|
|||
|
||||
return {'passwordCredentials': auth}
|
||||
|
||||
@classmethod
|
||||
def load_from_argparse_arguments(cls, namespace, **kwargs):
|
||||
if not (kwargs.get('password') or namespace.os_password):
|
||||
kwargs['password'] = utils.prompt_user_password()
|
||||
|
||||
return super(Password, cls).load_from_argparse_arguments(namespace,
|
||||
**kwargs)
|
||||
|
||||
@classmethod
|
||||
def get_options(cls):
|
||||
options = super(Password, cls).get_options()
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
from oslo_config import cfg
|
||||
|
||||
from keystoneclient.auth.identity.v3 import base
|
||||
from keystoneclient import utils
|
||||
|
||||
|
||||
__all__ = ['PasswordMethod', 'Password']
|
||||
|
@ -86,3 +87,11 @@ class Password(base.AuthConstructor):
|
|||
])
|
||||
|
||||
return options
|
||||
|
||||
@classmethod
|
||||
def load_from_argparse_arguments(cls, namespace, **kwargs):
|
||||
if not (kwargs.get('password') or namespace.os_password):
|
||||
kwargs['password'] = utils.prompt_user_password()
|
||||
|
||||
return super(Password, cls).load_from_argparse_arguments(namespace,
|
||||
**kwargs)
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import getpass
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
@ -296,13 +295,8 @@ class OpenStackIdentityShell(object):
|
|||
'--os-username or env[OS_USERNAME]')
|
||||
|
||||
if not args.os_password:
|
||||
# No password, If we've got a tty, try prompting for it
|
||||
if hasattr(sys.stdin, 'isatty') and sys.stdin.isatty():
|
||||
# Check for Ctl-D
|
||||
try:
|
||||
args.os_password = getpass.getpass('OS Password: ')
|
||||
except EOFError:
|
||||
pass
|
||||
args.os_password = utils.prompt_user_password()
|
||||
|
||||
# No password because we didn't have a tty or the
|
||||
# user Ctl-D when prompted?
|
||||
if not args.os_password:
|
||||
|
|
|
@ -10,9 +10,12 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import argparse
|
||||
import copy
|
||||
import uuid
|
||||
|
||||
import mock
|
||||
|
||||
from keystoneclient.auth.identity import v2
|
||||
from keystoneclient import exceptions
|
||||
from keystoneclient import session
|
||||
|
@ -294,3 +297,28 @@ class V2IdentityPlugin(utils.TestCase):
|
|||
def test_password_with_no_user_id_or_name(self):
|
||||
self.assertRaises(TypeError,
|
||||
v2.Password, self.TEST_URL, password=self.TEST_PASS)
|
||||
|
||||
@mock.patch('sys.stdin', autospec=True)
|
||||
def test_prompt_password(self, mock_stdin):
|
||||
parser = argparse.ArgumentParser()
|
||||
v2.Password.register_argparse_arguments(parser)
|
||||
|
||||
username = uuid.uuid4().hex
|
||||
auth_url = uuid.uuid4().hex
|
||||
tenant_id = uuid.uuid4().hex
|
||||
password = uuid.uuid4().hex
|
||||
|
||||
opts = parser.parse_args(['--os-username', username,
|
||||
'--os-auth-url', auth_url,
|
||||
'--os-tenant-id', tenant_id])
|
||||
|
||||
with mock.patch('getpass.getpass') as mock_getpass:
|
||||
mock_getpass.return_value = password
|
||||
mock_stdin.isatty = lambda: True
|
||||
|
||||
plugin = v2.Password.load_from_argparse_arguments(opts)
|
||||
|
||||
self.assertEqual(auth_url, plugin.auth_url)
|
||||
self.assertEqual(username, plugin.username)
|
||||
self.assertEqual(tenant_id, plugin.tenant_id)
|
||||
self.assertEqual(password, plugin.password)
|
||||
|
|
|
@ -10,9 +10,12 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import argparse
|
||||
import copy
|
||||
import uuid
|
||||
|
||||
import mock
|
||||
|
||||
from keystoneclient import access
|
||||
from keystoneclient.auth.identity import v3
|
||||
from keystoneclient.auth.identity.v3 import base as v3_base
|
||||
|
@ -531,3 +534,32 @@ class V3IdentityPlugin(utils.TestCase):
|
|||
s = session.Session()
|
||||
|
||||
self.assertRaises(exceptions.AuthorizationFailure, a.get_auth_ref, s)
|
||||
|
||||
@mock.patch('sys.stdin', autospec=True)
|
||||
def test_prompt_password(self, mock_stdin):
|
||||
parser = argparse.ArgumentParser()
|
||||
v3.Password.register_argparse_arguments(parser)
|
||||
|
||||
username = uuid.uuid4().hex
|
||||
user_domain_id = uuid.uuid4().hex
|
||||
auth_url = uuid.uuid4().hex
|
||||
project_id = uuid.uuid4().hex
|
||||
password = uuid.uuid4().hex
|
||||
|
||||
opts = parser.parse_args(['--os-username', username,
|
||||
'--os-auth-url', auth_url,
|
||||
'--os-user-domain-id', user_domain_id,
|
||||
'--os-project-id', project_id])
|
||||
|
||||
with mock.patch('getpass.getpass') as mock_getpass:
|
||||
mock_getpass.return_value = password
|
||||
mock_stdin.isatty = lambda: True
|
||||
|
||||
plugin = v3.Password.load_from_argparse_arguments(opts)
|
||||
|
||||
self.assertEqual(auth_url, plugin.auth_url)
|
||||
self.assertEqual(username, plugin.auth_methods[0].username)
|
||||
self.assertEqual(project_id, plugin.project_id)
|
||||
self.assertEqual(user_domain_id,
|
||||
plugin.auth_methods[0].user_domain_id)
|
||||
self.assertEqual(password, plugin.auth_methods[0].password)
|
||||
|
|
|
@ -10,8 +10,11 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import argparse
|
||||
import uuid
|
||||
|
||||
import mock
|
||||
|
||||
from keystoneclient.auth.identity.generic import password
|
||||
from keystoneclient.auth.identity import v2
|
||||
from keystoneclient.auth.identity import v3
|
||||
|
@ -66,3 +69,31 @@ class PasswordTests(utils.GenericPluginTestCase):
|
|||
def test_symbols(self):
|
||||
self.assertIs(v3.Password, v3_password.Password)
|
||||
self.assertIs(v3.PasswordMethod, v3_password.PasswordMethod)
|
||||
|
||||
@mock.patch('sys.stdin', autospec=True)
|
||||
def test_prompt_password(self, mock_stdin):
|
||||
parser = argparse.ArgumentParser()
|
||||
self.PLUGIN_CLASS.register_argparse_arguments(parser)
|
||||
|
||||
username = uuid.uuid4().hex
|
||||
user_domain_id = uuid.uuid4().hex
|
||||
auth_url = uuid.uuid4().hex
|
||||
project_id = uuid.uuid4().hex
|
||||
password = uuid.uuid4().hex
|
||||
|
||||
opts = parser.parse_args(['--os-username', username,
|
||||
'--os-auth-url', auth_url,
|
||||
'--os-user-domain-id', user_domain_id,
|
||||
'--os-project-id', project_id])
|
||||
|
||||
with mock.patch('getpass.getpass') as mock_getpass:
|
||||
mock_getpass.return_value = password
|
||||
mock_stdin.isatty = lambda: True
|
||||
|
||||
plugin = self.PLUGIN_CLASS.load_from_argparse_arguments(opts)
|
||||
|
||||
self.assertEqual(auth_url, plugin.auth_url)
|
||||
self.assertEqual(username, plugin._username)
|
||||
self.assertEqual(project_id, plugin._project_id)
|
||||
self.assertEqual(user_domain_id, plugin._user_domain_id)
|
||||
self.assertEqual(password, plugin._password)
|
||||
|
|
|
@ -147,6 +147,24 @@ def hash_signed_token(signed_text, mode='md5'):
|
|||
return hash_.hexdigest()
|
||||
|
||||
|
||||
def prompt_user_password():
|
||||
"""Prompt user for a password
|
||||
|
||||
Prompt for a password if stdin is a tty.
|
||||
"""
|
||||
password = None
|
||||
|
||||
# If stdin is a tty, try prompting for the password
|
||||
if hasattr(sys.stdin, 'isatty') and sys.stdin.isatty():
|
||||
# Check for Ctl-D
|
||||
try:
|
||||
password = getpass.getpass('Password: ')
|
||||
except EOFError:
|
||||
pass
|
||||
|
||||
return password
|
||||
|
||||
|
||||
def prompt_for_password():
|
||||
"""Prompt user for password if not provided so the password
|
||||
doesn't show up in the bash history.
|
||||
|
|
Loading…
Reference in New Issue