From 0936a74b5283e52bc2c09ceacc98ef541d669106 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Wed, 18 Feb 2026 10:14:04 -0800 Subject: [PATCH 1/5] Refactor --- src/main/client/connect.c | 11 +++++------ src/main/client/type.c | 21 +++++++++++++++------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/main/client/connect.c b/src/main/client/connect.c index 54f0e0cb26..9e89a39fad 100644 --- a/src/main/client/connect.c +++ b/src/main/client/connect.c @@ -144,6 +144,9 @@ int AerospikeClientConnect(AerospikeClient *self) return 0; } +extern void as_config_set_user_from_py_username_and_py_password( + as_config *config, PyObject *py_username, PyObject *py_password); + /** ******************************************************************************************************* * Establishes a connection to the Aerospike DB instance. @@ -176,12 +179,8 @@ PyObject *AerospikeClient_Connect(AerospikeClient *self, PyObject *args, return NULL; } - if (py_username && PyUnicode_Check(py_username) && py_password && - PyUnicode_Check(py_password)) { - char *username = (char *)PyUnicode_AsUTF8(py_username); - char *password = (char *)PyUnicode_AsUTF8(py_password); - as_config_set_user(&self->as->config, username, password); - } + as_config_set_user_from_py_username_and_py_password( + &self->as->config, py_username, py_password); if (AerospikeClientConnect(self) == -1) { return NULL; diff --git a/src/main/client/type.c b/src/main/client/type.c index b77e5a3290..cac394fa24 100644 --- a/src/main/client/type.c +++ b/src/main/client/type.c @@ -573,6 +573,18 @@ int does_py_dict_contain_valid_keys(as_error *err, PyObject *py_dict, #define CLIENT_CONFIG_DICTIONARY_ADJECTIVE_FOR_ERROR_MESSAGE "client config" +void as_config_set_user_from_py_username_and_py_password(as_config *config, + PyObject *py_username, + PyObject *py_password) +{ + if (py_username && PyUnicode_Check(py_username) && py_password && + PyUnicode_Check(py_password)) { + char *username = (char *)PyUnicode_AsUTF8(py_username); + char *password = (char *)PyUnicode_AsUTF8(py_password); + as_config_set_user(&config, username, password); + } +} + static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, PyObject *kwds) { @@ -1290,12 +1302,9 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, PyObject *py_user_name = PyDict_GetItemString(py_config, "user"); PyObject *py_user_pwd = PyDict_GetItemString(py_config, "password"); - if (py_user_name && PyUnicode_Check(py_user_name) && py_user_pwd && - PyUnicode_Check(py_user_pwd)) { - char *username = (char *)PyUnicode_AsUTF8(py_user_name); - char *password = (char *)PyUnicode_AsUTF8(py_user_pwd); - as_config_set_user(&config, username, password); - } + + as_config_set_user_from_py_username_and_py_password(&config, py_user_name, + py_user_pwd); self->as = aerospike_new(&config); From 9ae6fb8ad32d1778b49d2f4e7179790d4e134b01 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Wed, 18 Feb 2026 10:20:38 -0800 Subject: [PATCH 2/5] Add client side input validation since c client doesn't set as_error when either username or password is > 63 bytes long --- src/main/client/connect.c | 13 +++++++++---- src/main/client/type.c | 27 ++++++++++++++++++++++----- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/main/client/connect.c b/src/main/client/connect.c index 9e89a39fad..67831aef24 100644 --- a/src/main/client/connect.c +++ b/src/main/client/connect.c @@ -144,8 +144,9 @@ int AerospikeClientConnect(AerospikeClient *self) return 0; } -extern void as_config_set_user_from_py_username_and_py_password( - as_config *config, PyObject *py_username, PyObject *py_password); +extern as_status as_config_set_user_from_py_username_and_py_password( + as_error *err, as_config *config, PyObject *py_username, + PyObject *py_password); /** ******************************************************************************************************* @@ -179,8 +180,12 @@ PyObject *AerospikeClient_Connect(AerospikeClient *self, PyObject *args, return NULL; } - as_config_set_user_from_py_username_and_py_password( - &self->as->config, py_username, py_password); + if (as_config_set_user_from_py_username_and_py_password( + &err, &self->as->config, py_username, py_password) != + AEROSPIKE_OK) { + raise_exception(&err); + return NULL; + } if (AerospikeClientConnect(self) == -1) { return NULL; diff --git a/src/main/client/type.c b/src/main/client/type.c index cac394fa24..c1e6412e7a 100644 --- a/src/main/client/type.c +++ b/src/main/client/type.c @@ -573,16 +573,30 @@ int does_py_dict_contain_valid_keys(as_error *err, PyObject *py_dict, #define CLIENT_CONFIG_DICTIONARY_ADJECTIVE_FOR_ERROR_MESSAGE "client config" -void as_config_set_user_from_py_username_and_py_password(as_config *config, - PyObject *py_username, - PyObject *py_password) +as_status as_config_set_user_from_py_username_and_py_password( + as_error *err, as_config *config, PyObject *py_username, + PyObject *py_password) { if (py_username && PyUnicode_Check(py_username) && py_password && PyUnicode_Check(py_password)) { char *username = (char *)PyUnicode_AsUTF8(py_username); + if (username && strlen(username) >= AS_USER_SIZE) { + return as_error_update( + err, AEROSPIKE_ERR_PARAM, + "Username must be at most 63 characters long.") + } + char *password = (char *)PyUnicode_AsUTF8(py_password); + if (password && strlen(password) >= AS_PASSWORD_SIZE) { + return as_error_update( + err, AEROSPIKE_ERR_PARAM, + "Password must be at most 63 characters long.") + } + as_config_set_user(&config, username, password); } + + return AEROSPIKE_OK; } static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, @@ -1303,8 +1317,11 @@ static int AerospikeClient_Type_Init(AerospikeClient *self, PyObject *args, PyObject *py_user_name = PyDict_GetItemString(py_config, "user"); PyObject *py_user_pwd = PyDict_GetItemString(py_config, "password"); - as_config_set_user_from_py_username_and_py_password(&config, py_user_name, - py_user_pwd); + if (as_config_set_user_from_py_username_and_py_password( + &constructor_err, &config, py_user_name, py_user_pwd) != + AEROSPIKE_OK) { + goto RAISE_EXCEPTION_WITH_AS_ERROR; + } self->as = aerospike_new(&config); From 7fcbef2371f6b001dbd15f41fa10c9d74ced6b03 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Wed, 18 Feb 2026 14:50:01 -0800 Subject: [PATCH 3/5] fix --- src/main/client/type.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/client/type.c b/src/main/client/type.c index c1e6412e7a..565cd77ebe 100644 --- a/src/main/client/type.c +++ b/src/main/client/type.c @@ -593,7 +593,7 @@ as_status as_config_set_user_from_py_username_and_py_password( "Password must be at most 63 characters long.") } - as_config_set_user(&config, username, password); + as_config_set_user(config, username, password); } return AEROSPIKE_OK; From 23894f75230e0197ac2d9062b290751dd70e9ce2 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Wed, 18 Feb 2026 16:24:46 -0800 Subject: [PATCH 4/5] Add test case --- .../test_client_config_level_options.py | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/test/new_tests/test_client_config_level_options.py b/test/new_tests/test_client_config_level_options.py index f7b7c027e6..f79606bec8 100644 --- a/test/new_tests/test_client_config_level_options.py +++ b/test/new_tests/test_client_config_level_options.py @@ -523,9 +523,35 @@ def test_invalid_read_touch_ttl_percent(self, policy_name: str): }, # Tests that fail to connect should expect any of these exceptions pytest.raises((e.ConnectionError, e.TimeoutError, e.ClientError)) - ) + ), ] ) def test_client_class_constructor(self, config: dict, context): with context: aerospike.Client(config) + + LONG_USERNAME = "a" * 63 + LONG_PASSWORD = "a" * 63 + + @pytest.fixture + def setup_user_with_long_username_and_password(self): + self.as_connection.admin_create_user(self.LONG_USERNAME, self.LONG_PASSWORD, []) + + yield + + self.as_connection.admin_drop_user(self.LONG_USERNAME) + + @pytest.mark.parametrize( + "username, password", + [ + (LONG_USERNAME + "a", LONG_PASSWORD), + (LONG_USERNAME, LONG_PASSWORD + "a") + ] + ) + def test_passing_credentials_too_long(self, setup_user_with_long_username_and_password, username, password): + config = copy.deepcopy(gconfig) + config["user"] = username + config["password"] = password + + with pytest.raises(e.ParamError): + aerospike.client(config) From 4aea005c94a9b4b6145a9e0184a54a03ee9670ee Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Fri, 20 Feb 2026 10:03:46 -0800 Subject: [PATCH 5/5] fix test --- test/new_tests/test_client_config_level_options.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/new_tests/test_client_config_level_options.py b/test/new_tests/test_client_config_level_options.py index f79606bec8..f4f68bd5da 100644 --- a/test/new_tests/test_client_config_level_options.py +++ b/test/new_tests/test_client_config_level_options.py @@ -535,11 +535,11 @@ def test_client_class_constructor(self, config: dict, context): @pytest.fixture def setup_user_with_long_username_and_password(self): - self.as_connection.admin_create_user(self.LONG_USERNAME, self.LONG_PASSWORD, []) + self.client.admin_create_user(self.LONG_USERNAME, self.LONG_PASSWORD, []) yield - self.as_connection.admin_drop_user(self.LONG_USERNAME) + self.client.admin_drop_user(self.LONG_USERNAME) @pytest.mark.parametrize( "username, password",