Skip to content

Commit d609d78

Browse files
committed
RCBC-378: Implement change_password
1 parent 375b810 commit d609d78

File tree

3 files changed

+140
-0
lines changed

3 files changed

+140
-0
lines changed

ext/couchbase.cxx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4581,6 +4581,34 @@ cb_Backend_user_upsert(VALUE self, VALUE domain, VALUE user, VALUE timeout)
45814581
return Qnil;
45824582
}
45834583

4584+
static VALUE
4585+
cb_Backend_change_password(VALUE self, VALUE new_password, VALUE timeout)
4586+
{
4587+
const auto& cluster = cb_backend_to_cluster(self);
4588+
4589+
Check_Type(new_password, T_STRING);
4590+
4591+
try {
4592+
couchbase::core::operations::management::change_password_request req{};
4593+
cb_extract_timeout(req, timeout);
4594+
req.newPassword = cb_string_new(new_password);
4595+
auto barrier = std::make_shared<std::promise<couchbase::core::operations::management::change_password_response>>();
4596+
auto f = barrier->get_future();
4597+
cluster->execute(
4598+
req, [barrier](couchbase::core::operations::management::change_password_response&& resp) { barrier->set_value(std::move(resp)); });
4599+
if (auto resp = cb_wait_for_future(f); resp.ctx.ec) {
4600+
cb_throw_error_code(resp.ctx, "unable to change password");
4601+
}
4602+
4603+
return Qtrue;
4604+
} catch (const std::system_error& se) {
4605+
rb_exc_raise(cb_map_error_code(se.code(), fmt::format("failed to perform {}: {}", __func__, se.what()), false));
4606+
} catch (const ruby_exception& e) {
4607+
rb_exc_raise(e.exception_object());
4608+
}
4609+
return Qnil;
4610+
}
4611+
45844612
static void
45854613
cb_extract_group(const couchbase::core::management::rbac::group& entry, VALUE group)
45864614
{
@@ -8097,6 +8125,8 @@ init_backend(VALUE mCouchbase)
80978125
rb_define_method(cBackend, "group_drop", VALUE_FUNC(cb_Backend_group_drop), 2);
80988126
rb_define_method(cBackend, "group_upsert", VALUE_FUNC(cb_Backend_group_upsert), 2);
80998127

8128+
rb_define_method(cBackend, "change_password", VALUE_FUNC(cb_Backend_change_password), 2);
8129+
81008130
rb_define_method(cBackend, "cluster_enable_developer_preview!", VALUE_FUNC(cb_Backend_cluster_enable_developer_preview), 0);
81018131

81028132
rb_define_method(cBackend, "scope_get_all", VALUE_FUNC(cb_Backend_scope_get_all), 2);

lib/couchbase/management/user_manager.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,15 @@ def get_roles(options = GetRolesOptions.new)
101101
end
102102
end
103103

104+
# Changes the password of the currently authenticated user
105+
#
106+
# @param [ChangePasswordOptions] options
107+
#
108+
# @raise [ArgumentError]
109+
def change_password(new_password, options = ChangePasswordOptions.new)
110+
@backend.change_password(new_password, options.timeout)
111+
end
112+
104113
# Gets a group
105114
#
106115
# @param [String] group_name name of the group to get
@@ -213,6 +222,16 @@ def initialize
213222
end
214223
end
215224

225+
class ChangePasswordOptions
226+
# @return [Integer] the time in milliseconds allowed for the operation to complete
227+
attr_accessor :timeout
228+
229+
# @yieldparam [ChangePasswordOptions] self
230+
def initialize
231+
yield self if block_given?
232+
end
233+
end
234+
216235
class GetRolesOptions
217236
# @return [Integer] the time in milliseconds allowed for the operation to complete
218237
attr_accessor :timeout

test/user_manager_test.rb

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Copyright 2020-2021 Couchbase, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
require_relative "test_helper"
16+
17+
module Couchbase
18+
class UserManagerTest < Minitest::Test
19+
include TestUtilities
20+
21+
def setup
22+
connect
23+
@test_username = "test_user"
24+
@test_password = "a_password"
25+
@test_user = Management::User.new do |u|
26+
u.username = @test_username
27+
u.password = @test_password
28+
u.roles = [
29+
Management::Role.new do |r|
30+
r.name = "data_reader"
31+
r.bucket = "*"
32+
end,
33+
Management::Role.new do |r|
34+
r.name = "query_select"
35+
r.bucket = "*"
36+
end,
37+
Management::Role.new do |r|
38+
r.name = "data_writer"
39+
r.bucket = "*"
40+
end,
41+
Management::Role.new do |r|
42+
r.name = "query_insert"
43+
r.bucket = "*"
44+
end,
45+
Management::Role.new do |r|
46+
r.name = "query_delete"
47+
r.bucket = "*"
48+
end,
49+
Management::Role.new do |r|
50+
r.name = "query_manage_index"
51+
r.bucket = "*"
52+
end,
53+
]
54+
end
55+
@cluster.users.upsert_user(@test_user)
56+
end
57+
58+
def teardown
59+
connect
60+
@cluster.users.drop_user(@test_username)
61+
disconnect
62+
end
63+
64+
def test_change_password
65+
skip("#{name}: CAVES does not support change_password") if use_caves?
66+
67+
# Connect to the cluster with the test user
68+
orig_options = Cluster::ClusterOptions.new
69+
orig_options.authenticate(@test_username, @test_password)
70+
@cluster = Cluster.connect(@env.connection_string, orig_options)
71+
72+
# Change the test user's password
73+
new_password = "a_new_password"
74+
@cluster.users.change_password(new_password)
75+
76+
# Verify that the connection fails with the old password
77+
assert_raises(Error::AuthenticationFailure) { Cluster.connect(@env.connection_string, orig_options) }
78+
79+
# Verify that the connection succeeds with the new password
80+
new_options = Cluster::ClusterOptions.new
81+
new_options.authenticate(@test_username, new_password)
82+
@cluster = Cluster.connect(@env.connection_string, new_options)
83+
84+
# Change the password back to the original one
85+
@cluster.users.change_password(@test_password)
86+
87+
# Verify that the connection fails with the new password
88+
assert_raises(Error::AuthenticationFailure) { Cluster.connect(@env.connection_string, new_options) }
89+
end
90+
end
91+
end

0 commit comments

Comments
 (0)