Skip to content

Commit cb0ed4c

Browse files
committed
MB-68657 Add CLI support for temporary passwords
Add a user-manage --temporary-password flag which marks the password of an internal user as temporary. Change-Id: I86af3c0ba81cae9ff4858e9c0ab8df9ddc67e7ef Reviewed-on: https://review.couchbase.org/c/couchbase-cli/+/240154 Tested-by: Build Bot <build@couchbase.com> Well-Formed: Restriction Checker Reviewed-by: Matt Hall <matt.hall@couchbase.com>
1 parent a1429d7 commit cb0ed4c

4 files changed

Lines changed: 46 additions & 4 deletions

File tree

cbmgr.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4780,8 +4780,10 @@ def __init__(self):
47804780
group.add_argument("--group-name", dest="group", metavar="<group>", help="Group name")
47814781
group.add_argument("--group-description", dest="description", metavar="<text>", help="Group description")
47824782
group.add_argument("--ldap-ref", dest="ldap_ref", metavar="<ref>", help="LDAP group's distinguished name")
4783+
group.add_argument("--temporary-password", dest="temporary_password", action="store_true",
4784+
help="Force the user to change their password on next login (Enterprise Edition only)")
47834785

4784-
@rest_initialiser(cluster_init_check=True, version_check=True)
4786+
@rest_initialiser(cluster_init_check=True, version_check=True, enterprise_check=False)
47854787
def execute(self, opts):
47864788
num_selectors = sum([opts.delete, opts.list, opts.my_roles, opts.set, opts.get, opts.get_group,
47874789
opts.list_group, opts.delete_group, opts.set_group, opts.lock, opts.unlock])
@@ -4915,11 +4917,15 @@ def _set(self, opts):
49154917
if opts.rbac_pass is not None and opts.auth_domain == "external":
49164918
_warning("--rbac-password cannot be used with the external auth domain")
49174919
opts.rbac_pass = None
4920+
if opts.temporary_password and not self.enterprise:
4921+
_exit_if_errors(["--temporary-password is only supported on Enterprise Edition"])
4922+
if opts.temporary_password and opts.auth_domain == "external":
4923+
_exit_if_errors(["--temporary-password cannot be used for external users"])
49184924
if opts.auth_domain is None:
49194925
_exit_if_errors(["--auth-domain is required with the --set option"])
49204926

49214927
_, errors = self.rest.set_rbac_user(opts.rbac_user, opts.rbac_pass, opts.rbac_name, opts.roles,
4922-
opts.auth_domain, opts.groups)
4928+
opts.auth_domain, opts.groups, opts.temporary_password)
49234929
_exit_if_errors(errors)
49244930

49254931
if opts.roles is not None and "query_external_access" in opts.roles:

cluster_manager.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1595,7 +1595,7 @@ def my_roles(self):
15951595
url = f'{self.hostname}/whoami'
15961596
return self._get(url)
15971597

1598-
def set_rbac_user(self, username, password, name, roles, auth_domain, groups):
1598+
def set_rbac_user(self, username, password, name, roles, auth_domain, groups, temporary_password=None):
15991599
if auth_domain is None:
16001600
return None, ["The authentication type is required"]
16011601

@@ -1625,6 +1625,8 @@ def set_rbac_user(self, username, password, name, roles, auth_domain, groups):
16251625
params['groups'] = groups
16261626
elif 'groups' in defaults:
16271627
params['groups'] = ','.join(defaults['groups'])
1628+
if temporary_password:
1629+
params['temporaryPassword'] = 'true'
16281630

16291631
return self._put(url, params)
16301632

docs/modules/cli/pages/cbcli/couchbase-cli-user-manage.adoc

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ _couchbase-cli user-manage_ [--cluster <url>] [--username <user>] [--password <p
1919
[--set-group] [--delete-group] [--list-groups] [--get-group]
2020
[-- get] [--lock] [--unlock] [--rbac-username <username>]
2121
[--rbac-password <password>] [--rbac-name <name>] [--roles <roles_list>]
22-
[--auth-domain <domain>] [--user-groups <group>]
22+
[--auth-domain <domain>] [--user-groups <group>] [--temporary-password]
2323
[--group-description <text>] [--ldap-ref <ref>]
2424

2525
== DESCRIPTION
@@ -100,6 +100,10 @@ include::{partialsdir}/cbcli/part-common-options.adoc[]
100100
a user (--set) or when updating the users group, and
101101
should be specified as a comma separated list.
102102

103+
--temporary-password::
104+
Sets a temporary password which the user must change on their next login.
105+
This option can only be used with _local_ users.
106+
103107
--group-name <group>::
104108
Specifies the target group for the group operations (--set-group,
105109
--delete-group, --get-group).
@@ -456,6 +460,13 @@ $ couchbase-cli user-manage -c 127.0.0.1:8091 -u Administrator \
456460
--rbac-name "John Doe" --roles bucket_admin[default],replication_admin \
457461
--auth-domain local
458462
----
463+
To create a local user that with a temporary password (Enterprise Edition only):
464+
----
465+
$ couchbase-cli user-manage -c 127.0.0.1:8091 -u Administrator \
466+
-p password --set --rbac-username jdoe --rbac-password cbpass \
467+
--rbac-name "John Doe" --roles bucket_admin[default] \
468+
--auth-domain local --temporary-password
469+
----
459470
If you have external user source setup in your cluster and you want to add a
460471
user "John Doe" with username `jdoe` who should have the ability to manage only
461472
views for all bucket run the following command

test/test_cli.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2777,8 +2777,31 @@ def test_unlock(self):
27772777
self.assertIn('PATCH:/settings/rbac/users/local/username', self.server.trace)
27782778
expected_params = ['locked=false']
27792779
self.rest_parameter_match(expected_params)
2780+
2781+
def test_set_local_user_with_temporary_password(self):
2782+
self.no_error_run(self.command + ['--set', '--rbac-username', 'username', '--rbac-password', 'pwd',
2783+
'--auth-domain', 'local', '--roles', 'admin', '--rbac-name', 'name',
2784+
'--temporary-password'],
2785+
self.server_args)
2786+
self.assertIn('PUT:/settings/rbac/users/local/username', self.server.trace)
2787+
expected_params = ['name=name', 'password=pwd', 'roles=admin', 'temporaryPassword=true']
27802788
self.rest_parameter_match(expected_params)
27812789

2790+
def test_set_external_user_with_temporary_password(self):
2791+
self.system_exit_run(self.command + ['--set', '--rbac-username', 'username', '--auth-domain',
2792+
'external', '--roles', 'admin', '--rbac-name', 'name',
2793+
'--temporary-password'],
2794+
self.server_args)
2795+
self.assertIn('--temporary-password cannot be used for external users', self.str_output)
2796+
2797+
def test_set_local_user_with_temporary_password_community(self):
2798+
self.server_args['enterprise'] = False
2799+
self.system_exit_run(self.command + ['--set', '--rbac-username', 'username', '--rbac-password', 'pwd',
2800+
'--auth-domain', 'local', '--roles', 'admin', '--rbac-name', 'name',
2801+
'--temporary-password'],
2802+
self.server_args)
2803+
self.assertIn('--temporary-password is only supported on Enterprise Edition', self.str_output)
2804+
27822805

27832806
class TestMasterPassword(CommandTest):
27842807
def setUp(self):

0 commit comments

Comments
 (0)