summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTerry Howe <terrylhowe@gmail.com>2014-02-19 19:30:56 -0700
committerTerry Howe <terrylhowe@gmail.com>2014-02-21 14:42:22 -0700
commit033f27fe4dc4455c2f07978a273fd65faa653b67 (patch)
tree56126c4cd1a4d0aebbab6d0b7cfa6507ca3d195a
parent2f5e8232aa07a9031231ad7b4678b7c52c1effc4 (diff)
downloadpython-openstackclient-033f27fe4dc4455c2f07978a273fd65faa653b67.tar.gz
Add ability to prompt for passwords for user create and set
* Add get_password method to the utilities * Add --password-prompt option * Call the get_password method if a prompt is requested * Various tests Change-Id: I1786ad531e2a2fbcc21b8bc86aac0ccd7985995a Closes-Bug: 1100116
-rw-r--r--openstackclient/common/utils.py16
-rw-r--r--openstackclient/identity/v2_0/user.py17
-rw-r--r--openstackclient/identity/v3/user.py17
-rw-r--r--openstackclient/tests/common/test_utils.py59
-rw-r--r--openstackclient/tests/identity/v2_0/test_user.py73
-rw-r--r--openstackclient/tests/identity/v3/test_user.py87
6 files changed, 269 insertions, 0 deletions
diff --git a/openstackclient/common/utils.py b/openstackclient/common/utils.py
index 94ea2225..7cd877ef 100644
--- a/openstackclient/common/utils.py
+++ b/openstackclient/common/utils.py
@@ -15,6 +15,7 @@
"""Common client utilities"""
+import getpass
import logging
import os
import six
@@ -229,3 +230,18 @@ def get_effective_log_level():
for handler in root_log.handlers:
min_log_lvl = min(min_log_lvl, handler.level)
return min_log_lvl
+
+
+def get_password(stdin):
+ if hasattr(stdin, 'isatty') and stdin.isatty():
+ try:
+ while True:
+ first_pass = getpass.getpass("User password: ")
+ second_pass = getpass.getpass("Repeat user password: ")
+ if first_pass == second_pass:
+ return first_pass
+ print("The passwords entered were not the same")
+ except EOFError: # Ctl-D
+ raise exceptions.CommandError("Error reading password.")
+ raise exceptions.CommandError("There was a request to be prompted for a"
+ " password and a terminal was not detected.")
diff --git a/openstackclient/identity/v2_0/user.py b/openstackclient/identity/v2_0/user.py
index 371c45a9..abcafdd0 100644
--- a/openstackclient/identity/v2_0/user.py
+++ b/openstackclient/identity/v2_0/user.py
@@ -43,6 +43,12 @@ class CreateUser(show.ShowOne):
help='New user password',
)
parser.add_argument(
+ '--password-prompt',
+ dest="password_prompt",
+ action="store_true",
+ help='Prompt interactively for password',
+ )
+ parser.add_argument(
'--email',
metavar='<user-email>',
help='New user email address',
@@ -80,6 +86,8 @@ class CreateUser(show.ShowOne):
enabled = True
if parsed_args.disable:
enabled = False
+ if parsed_args.password_prompt:
+ parsed_args.password = utils.get_password(self.app.stdin)
user = identity_client.users.create(
parsed_args.name,
@@ -225,6 +233,12 @@ class SetUser(command.Command):
help='New user password',
)
parser.add_argument(
+ '--password-prompt',
+ dest="password_prompt",
+ action="store_true",
+ help='Prompt interactively for password',
+ )
+ parser.add_argument(
'--email',
metavar='<user-email>',
help='New user email address',
@@ -251,6 +265,9 @@ class SetUser(command.Command):
self.log.debug('take_action(%s)' % parsed_args)
identity_client = self.app.client_manager.identity
+ if parsed_args.password_prompt:
+ parsed_args.password = utils.get_password(self.app.stdin)
+
if (not parsed_args.name
and not parsed_args.name
and not parsed_args.password
diff --git a/openstackclient/identity/v3/user.py b/openstackclient/identity/v3/user.py
index 54ffe561..7e710ac0 100644
--- a/openstackclient/identity/v3/user.py
+++ b/openstackclient/identity/v3/user.py
@@ -44,6 +44,12 @@ class CreateUser(show.ShowOne):
help='New user password',
)
parser.add_argument(
+ '--password-prompt',
+ dest="password_prompt",
+ action="store_true",
+ help='Prompt interactively for password',
+ )
+ parser.add_argument(
'--email',
metavar='<user-email>',
help='New user email address',
@@ -97,6 +103,8 @@ class CreateUser(show.ShowOne):
enabled = True
if parsed_args.disable:
enabled = False
+ if parsed_args.password_prompt:
+ parsed_args.password = utils.get_password(self.app.stdin)
user = identity_client.users.create(
parsed_args.name,
@@ -274,6 +282,12 @@ class SetUser(command.Command):
help='New user password',
)
parser.add_argument(
+ '--password-prompt',
+ dest="password_prompt",
+ action="store_true",
+ help='Prompt interactively for password',
+ )
+ parser.add_argument(
'--email',
metavar='<user-email>',
help='New user email address',
@@ -310,6 +324,9 @@ class SetUser(command.Command):
self.log.debug('take_action(%s)' % parsed_args)
identity_client = self.app.client_manager.identity
+ if parsed_args.password_prompt:
+ parsed_args.password = utils.get_password(self.app.stdin)
+
if (not parsed_args.name
and not parsed_args.name
and not parsed_args.password
diff --git a/openstackclient/tests/common/test_utils.py b/openstackclient/tests/common/test_utils.py
new file mode 100644
index 00000000..0ad4ca9b
--- /dev/null
+++ b/openstackclient/tests/common/test_utils.py
@@ -0,0 +1,59 @@
+# Copyright 2012-2013 OpenStack, LLC.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+import mock
+
+from openstackclient.common import exceptions
+from openstackclient.common import utils
+from openstackclient.tests import utils as test_utils
+
+PASSWORD = "Pa$$w0rd"
+WASSPORD = "Wa$$p0rd"
+DROWSSAP = "dr0w$$aP"
+
+
+class TestUtils(test_utils.TestCase):
+
+ def test_get_password_good(self):
+ with mock.patch("getpass.getpass", return_value=PASSWORD):
+ mock_stdin = mock.Mock()
+ mock_stdin.isatty = mock.Mock()
+ mock_stdin.isatty.return_value = True
+ self.assertEqual(utils.get_password(mock_stdin), PASSWORD)
+
+ def test_get_password_bad_once(self):
+ answers = [PASSWORD, WASSPORD, DROWSSAP, DROWSSAP]
+ with mock.patch("getpass.getpass", side_effect=answers):
+ mock_stdin = mock.Mock()
+ mock_stdin.isatty = mock.Mock()
+ mock_stdin.isatty.return_value = True
+ self.assertEqual(utils.get_password(mock_stdin), DROWSSAP)
+
+ def test_get_password_no_tty(self):
+ mock_stdin = mock.Mock()
+ mock_stdin.isatty = mock.Mock()
+ mock_stdin.isatty.return_value = False
+ self.assertRaises(exceptions.CommandError,
+ utils.get_password,
+ mock_stdin)
+
+ def test_get_password_cntrl_d(self):
+ with mock.patch("getpass.getpass", side_effect=EOFError()):
+ mock_stdin = mock.Mock()
+ mock_stdin.isatty = mock.Mock()
+ mock_stdin.isatty.return_value = True
+ self.assertRaises(exceptions.CommandError,
+ utils.get_password,
+ mock_stdin)
diff --git a/openstackclient/tests/identity/v2_0/test_user.py b/openstackclient/tests/identity/v2_0/test_user.py
index a18d13d8..dfb358ff 100644
--- a/openstackclient/tests/identity/v2_0/test_user.py
+++ b/openstackclient/tests/identity/v2_0/test_user.py
@@ -14,6 +14,7 @@
#
import copy
+import mock
from openstackclient.identity.v2_0 import user
from openstackclient.tests import fakes
@@ -99,6 +100,7 @@ class TestUserCreate(TestUser):
]
verifylist = [
('name', identity_fakes.user_name),
+ ('password_prompt', False),
('password', 'secret')
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
@@ -130,6 +132,47 @@ class TestUserCreate(TestUser):
)
self.assertEqual(data, datalist)
+ def test_user_create_password_prompt(self):
+ arglist = [
+ '--password-prompt',
+ identity_fakes.user_name,
+ ]
+ verifylist = [
+ ('name', identity_fakes.user_name),
+ ('password_prompt', True)
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ mocker = mock.Mock()
+ mocker.return_value = 'abc123'
+ with mock.patch("openstackclient.common.utils.get_password", mocker):
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ 'tenant_id': None,
+ }
+ # UserManager.create(name, password, email, tenant_id=, enabled=)
+ self.users_mock.create.assert_called_with(
+ identity_fakes.user_name,
+ 'abc123',
+ None,
+ **kwargs
+ )
+
+ collist = ('email', 'enabled', 'id', 'name', 'project_id')
+ self.assertEqual(columns, collist)
+ datalist = (
+ identity_fakes.user_email,
+ True,
+ identity_fakes.user_id,
+ identity_fakes.user_name,
+ identity_fakes.project_id,
+ )
+ self.assertEqual(data, datalist)
+
def test_user_create_email(self):
arglist = [
'--email', 'barney@example.com',
@@ -498,6 +541,7 @@ class TestUserSet(TestUser):
verifylist = [
('name', None),
('password', 'secret'),
+ ('password_prompt', False),
('email', None),
('project', None),
('enable', False),
@@ -515,6 +559,35 @@ class TestUserSet(TestUser):
'secret',
)
+ def test_user_set_password_prompt(self):
+ arglist = [
+ '--password-prompt',
+ identity_fakes.user_name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('password', None),
+ ('password_prompt', True),
+ ('email', None),
+ ('project', None),
+ ('enable', False),
+ ('disable', False),
+ ('user', identity_fakes.user_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ mocker = mock.Mock()
+ mocker.return_value = 'abc123'
+ with mock.patch("openstackclient.common.utils.get_password", mocker):
+ self.cmd.take_action(parsed_args)
+
+ # UserManager.update_password(user, password)
+ self.users_mock.update_password.assert_called_with(
+ identity_fakes.user_id,
+ 'abc123',
+ )
+
def test_user_set_email(self):
arglist = [
'--email', 'barney@example.com',
diff --git a/openstackclient/tests/identity/v3/test_user.py b/openstackclient/tests/identity/v3/test_user.py
index 4321b047..af7b2f70 100644
--- a/openstackclient/tests/identity/v3/test_user.py
+++ b/openstackclient/tests/identity/v3/test_user.py
@@ -14,6 +14,7 @@
#
import copy
+import mock
from openstackclient.identity.v3 import user
from openstackclient.tests import fakes
@@ -118,6 +119,7 @@ class TestUserCreate(TestUser):
]
verifylist = [
('password', 'secret'),
+ ('password_prompt', False),
('enable', False),
('disable', False),
('name', identity_fakes.user_name),
@@ -155,6 +157,54 @@ class TestUserCreate(TestUser):
)
self.assertEqual(data, datalist)
+ def test_user_create_password_prompt(self):
+ arglist = [
+ '--password-prompt',
+ identity_fakes.user_name,
+ ]
+ verifylist = [
+ ('password', None),
+ ('password_prompt', True),
+ ('enable', False),
+ ('disable', False),
+ ('name', identity_fakes.user_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ mocker = mock.Mock()
+ mocker.return_value = 'abc123'
+ with mock.patch("openstackclient.common.utils.get_password", mocker):
+ columns, data = self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'default_project': None,
+ 'description': None,
+ 'domain': None,
+ 'email': None,
+ 'enabled': True,
+ 'password': 'abc123',
+ }
+ # UserManager.create(name, domain=, project=, password=, email=,
+ # description=, enabled=, default_project=)
+ self.users_mock.create.assert_called_with(
+ identity_fakes.user_name,
+ **kwargs
+ )
+
+ collist = ('domain_id', 'email', 'enabled', 'id', 'name', 'project_id')
+ self.assertEqual(columns, collist)
+ datalist = (
+ identity_fakes.domain_id,
+ identity_fakes.user_email,
+ True,
+ identity_fakes.user_id,
+ identity_fakes.user_name,
+ identity_fakes.project_id,
+ )
+ self.assertEqual(data, datalist)
+
def test_user_create_email(self):
arglist = [
'--email', 'barney@example.com',
@@ -761,6 +811,7 @@ class TestUserSet(TestUser):
verifylist = [
('name', None),
('password', 'secret'),
+ ('password_prompt', False),
('email', None),
('domain', None),
('project', None),
@@ -785,6 +836,42 @@ class TestUserSet(TestUser):
**kwargs
)
+ def test_user_set_password_prompt(self):
+ arglist = [
+ '--password-prompt',
+ identity_fakes.user_name,
+ ]
+ verifylist = [
+ ('name', None),
+ ('password', None),
+ ('password_prompt', True),
+ ('email', None),
+ ('domain', None),
+ ('project', None),
+ ('enable', False),
+ ('disable', False),
+ ('user', identity_fakes.user_name),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ # DisplayCommandBase.take_action() returns two tuples
+ mocker = mock.Mock()
+ mocker.return_value = 'abc123'
+ with mock.patch("openstackclient.common.utils.get_password", mocker):
+ self.cmd.take_action(parsed_args)
+
+ # Set expected values
+ kwargs = {
+ 'enabled': True,
+ 'password': 'abc123',
+ }
+ # UserManager.update(user, name=, domain=, project=, password=,
+ # email=, description=, enabled=, default_project=)
+ self.users_mock.update.assert_called_with(
+ identity_fakes.user_id,
+ **kwargs
+ )
+
def test_user_set_email(self):
arglist = [
'--email', 'barney@example.com',