Skip to content

Commit 3eab3f2

Browse files
authored
Python sync: add update_connection_password (#4548)
implemented sync update_connection_password Signed-off-by: Lior Sventitzky <liorsve@amazon.com>
1 parent 9dab7e5 commit 3eab3f2

File tree

5 files changed

+468
-16
lines changed

5 files changed

+468
-16
lines changed

python/glide-sync/glide_sync/glide_client.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,12 @@ def _init_ffi(self):
220220
unsigned long arg_count, const size_t *args, const unsigned long* args_len,
221221
const unsigned char* route_bytes, size_t route_bytes_len, uint64_t span_ptr
222222
);
223+
CommandResult* update_connection_password(
224+
const void* client_adapter_ptr,
225+
uintptr_t request_id,
226+
const char* password,
227+
bool immediate_authentication
228+
);
223229
"""
224230
)
225231

@@ -403,6 +409,60 @@ def _execute_command(
403409
)
404410
return self._handle_cmd_result(result)
405411

412+
def _update_connection_password(
413+
self,
414+
password: Optional[str],
415+
immediate_auth: bool = False,
416+
) -> TResult:
417+
"""
418+
Update the current connection password with a new password.
419+
420+
Note:
421+
This method updates the client's internal password configuration and does
422+
not perform password rotation on the server side.
423+
424+
This method is useful in scenarios where the server password has changed or when
425+
utilizing short-lived passwords for enhanced security. It allows the client to
426+
update its password to reconnect upon disconnection without the need to recreate
427+
the client instance. This ensures that the internal reconnection mechanism can
428+
handle reconnection seamlessly, preventing the loss of in-flight commands.
429+
430+
Args:
431+
password (`Optional[str]`): The new password to use for the connection,
432+
if `None` the password will be removed.
433+
immediate_auth (`bool`):
434+
`True`: The client will authenticate immediately with the new password against all connections, Using `AUTH`
435+
command. If password supplied is an empty string, auth will not be performed and warning will be returned.
436+
The default is `False`.
437+
438+
Returns:
439+
TOK: A simple OK response. If `immediate_auth=True` returns OK if the reauthenticate succeed.
440+
441+
Example:
442+
>>> client.update_connection_password("new_password", immediate_auth=True)
443+
'OK'
444+
"""
445+
if self._is_closed:
446+
raise ClosingError("Client is closed.")
447+
client_adapter_ptr = self._core_client
448+
if client_adapter_ptr == self._ffi.NULL:
449+
raise ValueError("Invalid client pointer.")
450+
451+
# Prepare C string for password
452+
c_password = (
453+
self._ffi.new("char[]", password.encode(ENCODING))
454+
if password is not None
455+
else self._ffi.new("char[]", b"")
456+
)
457+
458+
result = self._lib.update_connection_password(
459+
client_adapter_ptr,
460+
0, # Request ID (0 for sync use)
461+
c_password,
462+
immediate_auth,
463+
)
464+
return self._handle_cmd_result(result)
465+
406466
def close(self):
407467
if not self._is_closed:
408468
self._lib.close_client(self._core_client)

python/tests/async_tests/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ async def acl_glide_client(
9090
"""
9191
Client fot tests that use a server pre-configured with an ACL user.
9292
This function first uses the management client to register the USERNAME with INITIAL_PASSWORD,so that
93-
the client would be ablt to connect.
93+
the client would be able to connect.
9494
It then returns a client with this USERNAME and INITIAL_PASSWORD already set as its ServerCredentials.
9595
"""
9696

python/tests/sync_tests/conftest.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@
1717

1818
from tests.utils.cluster import ValkeyCluster
1919
from tests.utils.utils import (
20+
INITIAL_PASSWORD,
2021
NEW_PASSWORD,
22+
USERNAME,
2123
auth_client,
2224
config_set_new_password,
2325
create_sync_client_config,
26+
set_new_acl_username_with_password,
2427
)
2528

2629

@@ -37,6 +40,60 @@ def glide_sync_client(
3740
client.close()
3841

3942

43+
@pytest.fixture(scope="function")
44+
def management_sync_client(
45+
request,
46+
cluster_mode: bool,
47+
protocol: ProtocolVersion,
48+
) -> Generator[TSyncGlideClient, None, None]:
49+
"""Get async socket client for tests, used to manage the state when tests are on the client ability to connect"""
50+
client = create_sync_client(
51+
request, cluster_mode, protocol=protocol, lazy_connect=False
52+
)
53+
try:
54+
yield client
55+
finally:
56+
# Close the client first, then run teardown
57+
client.close()
58+
# Run teardown which has its own robust error handling
59+
sync_test_teardown(request, cluster_mode, protocol)
60+
61+
62+
@pytest.fixture(scope="function")
63+
def acl_glide_sync_client(
64+
request,
65+
cluster_mode: bool,
66+
protocol: ProtocolVersion,
67+
management_sync_client: TSyncGlideClient,
68+
) -> Generator[TSyncGlideClient, None, None]:
69+
"""
70+
Client fot tests that use a server pre-configured with an ACL user.
71+
This function first uses the management client to register the USERNAME with INITIAL_PASSWORD,so that
72+
the client would be able to connect.
73+
It then returns a client with this USERNAME and INITIAL_PASSWORD already set as its ServerCredentials.
74+
"""
75+
76+
set_new_acl_username_with_password(
77+
management_sync_client, USERNAME, INITIAL_PASSWORD
78+
)
79+
80+
client = create_sync_client(
81+
request,
82+
cluster_mode,
83+
protocol=protocol,
84+
credentials=ServerCredentials(username=USERNAME, password=INITIAL_PASSWORD),
85+
request_timeout=2000,
86+
lazy_connect=False,
87+
)
88+
try:
89+
yield client
90+
finally:
91+
# Close the client first, then run teardown
92+
client.close()
93+
# Run teardown which has its own robust error handling
94+
sync_test_teardown(request, cluster_mode, protocol)
95+
96+
4097
def create_sync_client(
4198
request,
4299
cluster_mode: bool,

0 commit comments

Comments
 (0)