Adding options to user cli

User options [1] can be set by making POST and PATCH
request for /v3/users API calls but cannot by openstack
CLI because of no user options defined in create and update
user CLI [2]. This patch adds the user options [1] in
create user and update user CLI.

[1] https://docs.openstack.org/keystone/latest/admin/resource-options.html#multi-factor-auth-rules
[2] https://docs.openstack.org/api-ref/identity/v3/#create-user

Change-Id: I4e41bae2e8cfbe92d52b14d856991bedcd44164f
This commit is contained in:
Vishakha Agarwal 2019-12-05 16:48:16 +05:30
parent c5719a12b5
commit 05da145eae
5 changed files with 1119 additions and 1 deletions

View File

@ -19,6 +19,12 @@ Create new user
[--password-prompt]
[--email <email-address>]
[--description <description>]
[--multi-factor-auth-rule <rule>]
[--ignore-lockout-failure-attempts| --no-ignore-lockout-failure-attempts]
[--ignore-password-expiry| --no-ignore-password-expiry]
[--ignore-change-password-upon-first-use| --no-ignore-change-password-upon-first-use]
[--enable-lock-password| --disable-lock-password]
[--enable-multi-factor-auth| --disable-multi-factor-auth]
[--enable | --disable]
[--or-show]
<user-name>
@ -56,6 +62,63 @@ Create new user
.. versionadded:: 3
.. option:: --ignore-lockout-failure-attempts
Opt into ignoring the number of times a user has authenticated and
locking out the user as a result
.. option:: --no-ignore-lockout-failure-attempts
Opt out of ignoring the number of times a user has authenticated
and locking out the user as a result
.. option:: --ignore-change-password-upon-first-use
Control if a user should be forced to change their password immediately
after they log into keystone for the first time. Opt into ignoring
the user to change their password during first time login in keystone.
.. option:: --no-ignore-change-password-upon-first-use
Control if a user should be forced to change their password immediately
after they log into keystone for the first time. Opt out of ignoring
the user to change their password during first time login in keystone.
.. option:: --ignore-password-expiry
Opt into allowing user to continue using passwords that may be
expired
.. option:: --no-ignore-password-expiry
Opt out of allowing user to continue using passwords that may be
expired
.. option:: --enable-lock-password
Disables the ability for a user to change its password through
self-service APIs
.. option:: --disable-lock-password
Enables the ability for a user to change its password through
self-service APIs
.. option:: --enable-multi-factor-auth
Enables the MFA (Multi Factor Auth)
.. option:: --disable-multi-factor-auth
Disables the MFA (Multi Factor Auth)
.. option:: --multi-factor-auth-rule <rule>
Set multi-factor auth rules. For example, to set a rule requiring the
"password" and "totp" auth methods to be provided,
use: "--multi-factor-auth-rule password,totp".
May be provided multiple times to set different rule combinations.
.. option:: --enable
Enable user (default)
@ -146,6 +209,12 @@ Set user properties
[--password-prompt]
[--email <email-address>]
[--description <description>]
[--multi-factor-auth-rule <rule>]
[--ignore-lockout-failure-attempts| --no-ignore-lockout-failure-attempts]
[--ignore-password-expiry| --no-ignore-password-expiry]
[--ignore-change-password-upon-first-use| --no-ignore-change-password-upon-first-use]
[--enable-lock-password| --disable-lock-password]
[--enable-multi-factor-auth| --disable-multi-factor-auth]
[--enable|--disable]
<user>
@ -187,6 +256,63 @@ Set user properties
.. versionadded:: 3
.. option:: --ignore-lockout-failure-attempts
Opt into ignoring the number of times a user has authenticated and
locking out the user as a result
.. option:: --no-ignore-lockout-failure-attempts
Opt out of ignoring the number of times a user has authenticated
and locking out the user as a result
.. option:: --ignore-change-password-upon-first-use
Control if a user should be forced to change their password immediately
after they log into keystone for the first time. Opt into ignoring
the user to change their password during first time login in keystone.
.. option:: --no-ignore-change-password-upon-first-use
Control if a user should be forced to change their password immediately
after they log into keystone for the first time. Opt out of ignoring
the user to change their password during first time login in keystone.
.. option:: --ignore-password-expiry
Opt into allowing user to continue using passwords that may be
expired
.. option:: --no-ignore-password-expiry
Opt out of allowing user to continue using passwords that may be
expired
.. option:: --enable-lock-password
Disables the ability for a user to change its password through
self-service APIs
.. option:: --disable-lock-password
Enables the ability for a user to change its password through
self-service APIs
.. option:: --enable-multi-factor-auth
Enables the MFA (Multi Factor Auth)
.. option:: --disable-multi-factor-auth
Disables the MFA (Multi Factor Auth)
.. option:: --multi-factor-auth-rule <rule>
Set multi-factor auth rules. For example, to set a rule requiring the
"password" and "totp" auth methods to be provided,
use: "--multi-factor-auth-rule password,totp".
May be provided multiple times to set different rule combinations.
.. option:: --enable
Enable user (default)

View File

@ -30,6 +30,114 @@ from openstackclient.identity import common
LOG = logging.getLogger(__name__)
def _get_options_for_user(identity_client, parsed_args):
options = {}
if parsed_args.ignore_lockout_failure_attempts:
options['ignore_lockout_failure_attempts'] = True
if parsed_args.no_ignore_lockout_failure_attempts:
options['ignore_lockout_failure_attempts'] = False
if parsed_args.ignore_password_expiry:
options['ignore_password_expiry'] = True
if parsed_args.no_ignore_password_expiry:
options['ignore_password_expiry'] = False
if parsed_args.ignore_change_password_upon_first_use:
options['ignore_change_password_upon_first_use'] = True
if parsed_args.no_ignore_change_password_upon_first_use:
options['ignore_change_password_upon_first_use'] = False
if parsed_args.enable_lock_password:
options['lock_password'] = True
if parsed_args.disable_lock_password:
options['lock_password'] = False
if parsed_args.enable_multi_factor_auth:
options['multi_factor_auth_enabled'] = True
if parsed_args.disable_multi_factor_auth:
options['multi_factor_auth_enabled'] = False
if parsed_args.multi_factor_auth_rule:
auth_rules = [rule.split(",") for rule in
parsed_args.multi_factor_auth_rule]
if auth_rules:
options['multi_factor_auth_rules'] = auth_rules
return options
def _add_user_options(parser):
# Add additional user options
parser.add_argument(
'--ignore-lockout-failure-attempts',
action="store_true",
help=_('Opt into ignoring the number of times a user has '
'authenticated and locking out the user as a result'),
)
parser.add_argument(
'--no-ignore-lockout-failure-attempts',
action="store_true",
help=_('Opt out of ignoring the number of times a user has '
'authenticated and locking out the user as a result'),
)
parser.add_argument(
'--ignore-password-expiry',
action="store_true",
help=_('Opt into allowing user to continue using passwords that '
'may be expired'),
)
parser.add_argument(
'--no-ignore-password-expiry',
action="store_true",
help=_('Opt out of allowing user to continue using passwords '
'that may be expired'),
)
parser.add_argument(
'--ignore-change-password-upon-first-use',
action="store_true",
help=_('Control if a user should be forced to change their password '
'immediately after they log into keystone for the first time. '
'Opt into ignoring the user to change their password during '
'first time login in keystone'),
)
parser.add_argument(
'--no-ignore-change-password-upon-first-use',
action="store_true",
help=_('Control if a user should be forced to change their password '
'immediately after they log into keystone for the first time. '
'Opt out of ignoring the user to change their password during '
'first time login in keystone'),
)
parser.add_argument(
'--enable-lock-password',
action="store_true",
help=_('Disables the ability for a user to change its password '
'through self-service APIs'),
)
parser.add_argument(
'--disable-lock-password',
action="store_true",
help=_('Enables the ability for a user to change its password '
'through self-service APIs'),
)
parser.add_argument(
'--enable-multi-factor-auth',
action="store_true",
help=_('Enables the MFA (Multi Factor Auth)'),
)
parser.add_argument(
'--disable-multi-factor-auth',
action="store_true",
help=_('Disables the MFA (Multi Factor Auth)'),
)
parser.add_argument(
'--multi-factor-auth-rule',
metavar='<rule>',
action="append",
default=[],
help=_('Set multi-factor auth rules. For example, to set a rule '
'requiring the "password" and "totp" auth methods to be '
'provided, use: "--multi-factor-auth-rule password,totp". '
'May be provided multiple times to set different rule '
'combinations.')
)
class CreateUser(command.ShowOne):
_description = _("Create new user")
@ -72,6 +180,8 @@ class CreateUser(command.ShowOne):
metavar='<description>',
help=_('User description'),
)
_add_user_options(parser)
enable_group = parser.add_mutually_exclusive_group()
enable_group.add_argument(
'--enable',
@ -113,6 +223,7 @@ class CreateUser(command.ShowOne):
if not parsed_args.password:
LOG.warning(_("No password was supplied, authentication will fail "
"when a user does not have a password."))
options = _get_options_for_user(identity_client, parsed_args)
try:
user = identity_client.users.create(
@ -122,7 +233,8 @@ class CreateUser(command.ShowOne):
password=parsed_args.password,
email=parsed_args.email,
description=parsed_args.description,
enabled=enabled
enabled=enabled,
options=options,
)
except ks_exc.Conflict:
if parsed_args.or_show:
@ -333,6 +445,8 @@ class SetUser(command.Command):
metavar='<description>',
help=_('Set user description'),
)
_add_user_options(parser)
enable_group = parser.add_mutually_exclusive_group()
enable_group.add_argument(
'--enable',
@ -390,6 +504,10 @@ class SetUser(command.Command):
if parsed_args.disable:
kwargs['enabled'] = False
options = _get_options_for_user(identity_client, parsed_args)
if options:
kwargs['options'] = options
identity_client.users.update(user.id, **kwargs)

View File

@ -108,6 +108,9 @@ MAPPING_RESPONSE_2 = {
"rules": MAPPING_RULES_2
}
mfa_opt1 = 'password,totp'
mfa_opt2 = 'password'
project_id = '8-9-64'
project_name = 'beatles'
project_description = 'Fab Four'

View File

@ -111,6 +111,7 @@ class TestUserCreate(TestUser):
'description': None,
'domain': None,
'email': None,
'options': {},
'enabled': True,
'password': None,
}
@ -150,6 +151,7 @@ class TestUserCreate(TestUser):
'description': None,
'domain': None,
'email': None,
'options': {},
'enabled': True,
'password': 'secret',
}
@ -190,6 +192,7 @@ class TestUserCreate(TestUser):
'description': None,
'domain': None,
'email': None,
'options': {},
'enabled': True,
'password': 'abc123',
}
@ -228,6 +231,7 @@ class TestUserCreate(TestUser):
'domain': None,
'email': 'barney@example.com',
'enabled': True,
'options': {},
'password': None,
}
# UserManager.create(name=, domain=, project=, password=, email=,
@ -265,6 +269,7 @@ class TestUserCreate(TestUser):
'domain': None,
'email': None,
'enabled': True,
'options': {},
'password': None,
}
# UserManager.create(name=, domain=, project=, password=, email=,
@ -311,6 +316,7 @@ class TestUserCreate(TestUser):
'description': None,
'domain': None,
'email': None,
'options': {},
'enabled': True,
'password': None,
}
@ -356,6 +362,7 @@ class TestUserCreate(TestUser):
'description': None,
'domain': self.domain.id,
'email': None,
'options': {},
'enabled': True,
'password': None,
}
@ -392,6 +399,7 @@ class TestUserCreate(TestUser):
'description': None,
'domain': None,
'email': None,
'options': {},
'enabled': True,
'password': None,
}
@ -428,6 +436,7 @@ class TestUserCreate(TestUser):
'description': None,
'domain': None,
'email': None,
'options': {},
'enabled': False,
'password': None,
}
@ -438,6 +447,471 @@ class TestUserCreate(TestUser):
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
def test_user_create_ignore_lockout_failure_attempts(self):
arglist = [
'--ignore-lockout-failure-attempts',
self.user.name,
]
verifylist = [
('ignore_lockout_failure_attempts', True),
('enable', False),
('disable', False),
('name', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# In base command class ShowOne in cliff, abstract method take_action()
# returns a two-part tuple with a tuple of column names and a tuple of
# data to be shown.
columns, data = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'name': self.user.name,
'default_project': None,
'description': None,
'domain': None,
'email': None,
'enabled': True,
'options': {'ignore_lockout_failure_attempts': True},
'password': None,
}
# UserManager.create(name=, domain=, project=, password=, email=,
# description=, enabled=, default_project=)
self.users_mock.create.assert_called_with(
**kwargs
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
def test_user_create_no_ignore_lockout_failure_attempts(self):
arglist = [
'--no-ignore-lockout-failure-attempts',
self.user.name,
]
verifylist = [
('no_ignore_lockout_failure_attempts', True),
('enable', False),
('disable', False),
('name', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# In base command class ShowOne in cliff, abstract method take_action()
# returns a two-part tuple with a tuple of column names and a tuple of
# data to be shown.
columns, data = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'name': self.user.name,
'default_project': None,
'description': None,
'domain': None,
'email': None,
'enabled': True,
'options': {'ignore_lockout_failure_attempts': False},
'password': None,
}
# UserManager.create(name=, domain=, project=, password=, email=,
# description=, enabled=, default_project=)
self.users_mock.create.assert_called_with(
**kwargs
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
def test_user_create_ignore_password_expiry(self):
arglist = [
'--ignore-password-expiry',
self.user.name,
]
verifylist = [
('ignore_password_expiry', True),
('enable', False),
('disable', False),
('name', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# In base command class ShowOne in cliff, abstract method take_action()
# returns a two-part tuple with a tuple of column names and a tuple of
# data to be shown.
columns, data = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'name': self.user.name,
'default_project': None,
'description': None,
'domain': None,
'email': None,
'enabled': True,
'options': {'ignore_password_expiry': True},
'password': None,
}
# UserManager.create(name=, domain=, project=, password=, email=,
# description=, enabled=, default_project=)
self.users_mock.create.assert_called_with(
**kwargs
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
def test_user_create_no_ignore_password_expiry(self):
arglist = [
'--no-ignore-password-expiry',
self.user.name,
]
verifylist = [
('no_ignore_password_expiry', True),
('enable', False),
('disable', False),
('name', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# In base command class ShowOne in cliff, abstract method take_action()
# returns a two-part tuple with a tuple of column names and a tuple of
# data to be shown.
columns, data = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'name': self.user.name,
'default_project': None,
'description': None,
'domain': None,
'email': None,
'enabled': True,
'options': {'ignore_password_expiry': False},
'password': None,
}
# UserManager.create(name=, domain=, project=, password=, email=,
# description=, enabled=, default_project=)
self.users_mock.create.assert_called_with(
**kwargs
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
def test_user_create_ignore_change_password_upon_first_use(self):
arglist = [
'--ignore-change-password-upon-first-use',
self.user.name,
]
verifylist = [
('ignore_change_password_upon_first_use', True),
('enable', False),
('disable', False),
('name', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# In base command class ShowOne in cliff, abstract method take_action()
# returns a two-part tuple with a tuple of column names and a tuple of
# data to be shown.
columns, data = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'name': self.user.name,
'default_project': None,
'description': None,
'domain': None,
'email': None,
'enabled': True,
'options': {'ignore_change_password_upon_first_use': True},
'password': None,
}
# UserManager.create(name=, domain=, project=, password=, email=,
# description=, enabled=, default_project=)
self.users_mock.create.assert_called_with(
**kwargs
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
def test_user_create_no_ignore_change_password_upon_first_use(self):
arglist = [
'--no-ignore-change-password-upon-first-use',
self.user.name,
]
verifylist = [
('no_ignore_change_password_upon_first_use', True),
('enable', False),
('disable', False),
('name', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# In base command class ShowOne in cliff, abstract method take_action()
# returns a two-part tuple with a tuple of column names and a tuple of
# data to be shown.
columns, data = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'name': self.user.name,
'default_project': None,
'description': None,
'domain': None,
'email': None,
'enabled': True,
'options': {'ignore_change_password_upon_first_use': False},
'password': None,
}
# UserManager.create(name=, domain=, project=, password=, email=,
# description=, enabled=, default_project=)
self.users_mock.create.assert_called_with(
**kwargs
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
def test_user_create_enables_lock_password(self):
arglist = [
'--enable-lock-password',
self.user.name,
]
verifylist = [
('enable_lock_password', True),
('enable', False),
('disable', False),
('name', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# In base command class ShowOne in cliff, abstract method take_action()
# returns a two-part tuple with a tuple of column names and a tuple of
# data to be shown.
columns, data = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'name': self.user.name,
'default_project': None,
'description': None,
'domain': None,
'email': None,
'enabled': True,
'options': {'lock_password': True},
'password': None,
}
# UserManager.create(name=, domain=, project=, password=, email=,
# description=, enabled=, default_project=)
self.users_mock.create.assert_called_with(
**kwargs
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
def test_user_create_disables_lock_password(self):
arglist = [
'--disable-lock-password',
self.user.name,
]
verifylist = [
('disable_lock_password', True),
('enable', False),
('disable', False),
('name', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# In base command class ShowOne in cliff, abstract method take_action()
# returns a two-part tuple with a tuple of column names and a tuple of
# data to be shown.
columns, data = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'name': self.user.name,
'default_project': None,
'description': None,
'domain': None,
'email': None,
'enabled': True,
'options': {'lock_password': False},
'password': None,
}
# UserManager.create(name=, domain=, project=, password=, email=,
# description=, enabled=, default_project=)
self.users_mock.create.assert_called_with(
**kwargs
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
def test_user_create_enable_multi_factor_auth(self):
arglist = [
'--enable-multi-factor-auth',
self.user.name,
]
verifylist = [
('enable_multi_factor_auth', True),
('enable', False),
('disable', False),
('name', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# In base command class ShowOne in cliff, abstract method take_action()
# returns a two-part tuple with a tuple of column names and a tuple of
# data to be shown.
columns, data = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'name': self.user.name,
'default_project': None,
'description': None,
'domain': None,
'email': None,
'enabled': True,
'options': {'multi_factor_auth_enabled': True},
'password': None,
}
# UserManager.create(name=, domain=, project=, password=, email=,
# description=, enabled=, default_project=)
self.users_mock.create.assert_called_with(
**kwargs
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
def test_user_create_disable_multi_factor_auth(self):
arglist = [
'--disable-multi-factor-auth',
self.user.name,
]
verifylist = [
('disable_multi_factor_auth', True),
('enable', False),
('disable', False),
('name', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# In base command class ShowOne in cliff, abstract method take_action()
# returns a two-part tuple with a tuple of column names and a tuple of
# data to be shown.
columns, data = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'name': self.user.name,
'default_project': None,
'description': None,
'domain': None,
'email': None,
'enabled': True,
'options': {'multi_factor_auth_enabled': False},
'password': None,
}
# UserManager.create(name=, domain=, project=, password=, email=,
# description=, enabled=, default_project=)
self.users_mock.create.assert_called_with(
**kwargs
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
def test_user_create_option_with_multi_factor_auth_rule(self):
arglist = [
'--multi-factor-auth-rule', identity_fakes.mfa_opt1,
'--multi-factor-auth-rule', identity_fakes.mfa_opt2,
self.user.name,
]
verifylist = [
('multi_factor_auth_rule', [identity_fakes.mfa_opt1,
identity_fakes.mfa_opt2]),
('enable', False),
('disable', False),
('name', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# In base command class ShowOne in cliff, abstract method take_action()
# returns a two-part tuple with a tuple of column names and a tuple of
# data to be shown.
columns, data = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'name': self.user.name,
'default_project': None,
'description': None,
'domain': None,
'email': None,
'enabled': True,
'options': {'multi_factor_auth_rules': [["password", "totp"],
["password"]]},
'password': None,
}
# UserManager.create(name=, domain=, project=, password=, email=,
# description=, enabled=, default_project=)
self.users_mock.create.assert_called_with(
**kwargs
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
def test_user_create_with_multiple_options(self):
arglist = [
'--ignore-password-expiry',
'--disable-multi-factor-auth',
'--multi-factor-auth-rule', identity_fakes.mfa_opt1,
self.user.name,
]
verifylist = [
('ignore_password_expiry', True),
('disable_multi_factor_auth', True),
('multi_factor_auth_rule', [identity_fakes.mfa_opt1]),
('enable', False),
('disable', False),
('name', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# In base command class ShowOne in cliff, abstract method take_action()
# returns a two-part tuple with a tuple of column names and a tuple of
# data to be shown.
columns, data = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'name': self.user.name,
'default_project': None,
'description': None,
'domain': None,
'email': None,
'enabled': True,
'options': {'ignore_password_expiry': True,
'multi_factor_auth_enabled': False,
'multi_factor_auth_rules': [["password", "totp"]]},
'password': None,
}
# UserManager.create(name=, domain=, project=, password=, email=,
# description=, enabled=, default_project=)
self.users_mock.create.assert_called_with(
**kwargs
)
self.assertEqual(self.columns, columns)
self.assertEqual(self.datalist, data)
class TestUserDelete(TestUser):
@ -1007,6 +1481,384 @@ class TestUserSet(TestUser):
)
self.assertIsNone(result)
def test_user_set_ignore_lockout_failure_attempts(self):
arglist = [
'--ignore-lockout-failure-attempts',
self.user.name,
]
verifylist = [
('name', None),
('password', None),
('email', None),
('ignore_lockout_failure_attempts', True),
('project', None),
('enable', False),
('disable', False),
('user', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'enabled': True,
'options': {'ignore_lockout_failure_attempts': True},
}
# UserManager.update(user, name=, domain=, project=, password=,
# email=, description=, enabled=, default_project=)
self.users_mock.update.assert_called_with(
self.user.id,
**kwargs
)
self.assertIsNone(result)
def test_user_set_no_ignore_lockout_failure_attempts(self):
arglist = [
'--no-ignore-lockout-failure-attempts',
self.user.name,
]
verifylist = [
('name', None),
('password', None),
('email', None),
('no_ignore_lockout_failure_attempts', True),
('project', None),
('enable', False),
('disable', False),
('user', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'enabled': True,
'options': {'ignore_lockout_failure_attempts': False},
}
# UserManager.update(user, name=, domain=, project=, password=,
# email=, description=, enabled=, default_project=)
self.users_mock.update.assert_called_with(
self.user.id,
**kwargs
)
self.assertIsNone(result)
def test_user_set_ignore_password_expiry(self):
arglist = [
'--ignore-password-expiry',
self.user.name,
]
verifylist = [
('name', None),
('password', None),
('email', None),
('ignore_password_expiry', True),
('project', None),
('enable', False),
('disable', False),
('user', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'enabled': True,
'options': {'ignore_password_expiry': True},
}
# UserManager.update(user, name=, domain=, project=, password=,
# email=, description=, enabled=, default_project=)
self.users_mock.update.assert_called_with(
self.user.id,
**kwargs
)
self.assertIsNone(result)
def test_user_set_no_ignore_password_expiry(self):
arglist = [
'--no-ignore-password-expiry',
self.user.name,
]
verifylist = [
('name', None),
('password', None),
('email', None),
('no_ignore_password_expiry', True),
('project', None),
('enable', False),
('disable', False),
('user', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'enabled': True,
'options': {'ignore_password_expiry': False},
}
# UserManager.update(user, name=, domain=, project=, password=,
# email=, description=, enabled=, default_project=)
self.users_mock.update.assert_called_with(
self.user.id,
**kwargs
)
self.assertIsNone(result)
def test_user_set_ignore_change_password_upon_first_use(self):
arglist = [
'--ignore-change-password-upon-first-use',
self.user.name,
]
verifylist = [
('name', None),
('password', None),
('email', None),
('ignore_change_password_upon_first_use', True),
('project', None),
('enable', False),
('disable', False),
('user', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'enabled': True,
'options': {'ignore_change_password_upon_first_use': True},
}
# UserManager.update(user, name=, domain=, project=, password=,
# email=, description=, enabled=, default_project=)
self.users_mock.update.assert_called_with(
self.user.id,
**kwargs
)
self.assertIsNone(result)
def test_user_set_no_ignore_change_password_upon_first_use(self):
arglist = [
'--no-ignore-change-password-upon-first-use',
self.user.name,
]
verifylist = [
('name', None),
('password', None),
('email', None),
('no_ignore_change_password_upon_first_use', True),
('project', None),
('enable', False),
('disable', False),
('user', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'enabled': True,
'options': {'ignore_change_password_upon_first_use': False},
}
# UserManager.update(user, name=, domain=, project=, password=,
# email=, description=, enabled=, default_project=)
self.users_mock.update.assert_called_with(
self.user.id,
**kwargs
)
self.assertIsNone(result)
def test_user_set_enable_lock_password(self):
arglist = [
'--enable-lock-password',
self.user.name,
]
verifylist = [
('name', None),
('password', None),
('email', None),
('enable_lock_password', True),
('project', None),
('enable', False),
('disable', False),
('user', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'enabled': True,
'options': {'lock_password': True},
}
# UserManager.update(user, name=, domain=, project=, password=,
# email=, description=, enabled=, default_project=)
self.users_mock.update.assert_called_with(
self.user.id,
**kwargs
)
self.assertIsNone(result)
def test_user_set_disable_lock_password(self):
arglist = [
'--disable-lock-password',
self.user.name,
]
verifylist = [
('name', None),
('password', None),
('email', None),
('disable_lock_password', True),
('project', None),
('enable', False),
('disable', False),
('user', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'enabled': True,
'options': {'lock_password': False},
}
# UserManager.update(user, name=, domain=, project=, password=,
# email=, description=, enabled=, default_project=)
self.users_mock.update.assert_called_with(
self.user.id,
**kwargs
)
self.assertIsNone(result)
def test_user_set_enable_multi_factor_auth(self):
arglist = [
'--enable-multi-factor-auth',
self.user.name,
]
verifylist = [
('name', None),
('password', None),
('email', None),
('enable_multi_factor_auth', True),
('project', None),
('enable', False),
('disable', False),
('user', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'enabled': True,
'options': {'multi_factor_auth_enabled': True},
}
# UserManager.update(user, name=, domain=, project=, password=,
# email=, description=, enabled=, default_project=)
self.users_mock.update.assert_called_with(
self.user.id,
**kwargs
)
self.assertIsNone(result)
def test_user_set_disable_multi_factor_auth(self):
arglist = [
'--disable-multi-factor-auth',
self.user.name,
]
verifylist = [
('name', None),
('password', None),
('email', None),
('disable_multi_factor_auth', True),
('project', None),
('enable', False),
('disable', False),
('user', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'enabled': True,
'options': {'multi_factor_auth_enabled': False},
}
# UserManager.update(user, name=, domain=, project=, password=,
# email=, description=, enabled=, default_project=)
self.users_mock.update.assert_called_with(
self.user.id,
**kwargs
)
self.assertIsNone(result)
def test_user_set_option_multi_factor_auth_rule(self):
arglist = [
'--multi-factor-auth-rule', identity_fakes.mfa_opt1,
self.user.name,
]
verifylist = [
('name', None),
('password', None),
('email', None),
('multi_factor_auth_rule', [identity_fakes.mfa_opt1]),
('project', None),
('enable', False),
('disable', False),
('user', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'enabled': True,
'options': {'multi_factor_auth_rules': [["password", "totp"]]}}
# UserManager.update(user, name=, domain=, project=, password=,
# email=, description=, enabled=, default_project=)
self.users_mock.update.assert_called_with(
self.user.id,
**kwargs
)
self.assertIsNone(result)
def test_user_set_with_multiple_options(self):
arglist = [
'--ignore-password-expiry',
'--enable-multi-factor-auth',
'--multi-factor-auth-rule', identity_fakes.mfa_opt1,
self.user.name,
]
verifylist = [
('name', None),
('password', None),
('email', None),
('ignore_password_expiry', True),
('enable_multi_factor_auth', True),
('multi_factor_auth_rule', [identity_fakes.mfa_opt1]),
('project', None),
('enable', False),
('disable', False),
('user', self.user.name),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
result = self.cmd.take_action(parsed_args)
# Set expected values
kwargs = {
'enabled': True,
'options': {'ignore_password_expiry': True,
'multi_factor_auth_enabled': True,
'multi_factor_auth_rules': [["password", "totp"]]}}
# UserManager.update(user, name=, domain=, project=, password=,
# email=, description=, enabled=, default_project=)
self.users_mock.update.assert_called_with(
self.user.id,
**kwargs
)
self.assertIsNone(result)
class TestUserSetPassword(TestUser):

View File

@ -0,0 +1,19 @@
---
features:
- |
Added the below mentioned parameters to the user create and set commands.
* --ignore-lockout-failure-attempts
* --no-ignore-lockout-failure-attempts
* --ignore-password-expiry
* --no-ignore-password-expiry
* --ignore-change-password-upon-first-use
* --no-ignore-change-password-upon-first-use
* --enable-lock-password
* --disable-lock-password
* --enable-multi-factor-auth
* --disable-multi-factor-auth
* --multi-factor-auth-rule
This will now allow users to set user options via CLI.
<https://docs.openstack.org/keystone/latest/admin/resource-options.html#user-options>