diff --git a/src/main/client/connect.c b/src/main/client/connect.c index 54f0e0cb26..67831aef24 100644 --- a/src/main/client/connect.c +++ b/src/main/client/connect.c @@ -144,6 +144,10 @@ int AerospikeClientConnect(AerospikeClient *self) return 0; } +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); + /** ******************************************************************************************************* * Establishes a connection to the Aerospike DB instance. @@ -176,11 +180,11 @@ 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); + 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) { diff --git a/src/main/client/type.c b/src/main/client/type.c index b77e5a3290..565cd77ebe 100644 --- a/src/main/client/type.c +++ b/src/main/client/type.c @@ -573,6 +573,32 @@ int does_py_dict_contain_valid_keys(as_error *err, PyObject *py_dict, #define CLIENT_CONFIG_DICTIONARY_ADJECTIVE_FOR_ERROR_MESSAGE "client config" +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, PyObject *kwds) { @@ -1290,11 +1316,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"); - 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); + + 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); diff --git a/test/new_tests/test_client_config_level_options.py b/test/new_tests/test_client_config_level_options.py index f7b7c027e6..f4f68bd5da 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.client.admin_create_user(self.LONG_USERNAME, self.LONG_PASSWORD, []) + + yield + + self.client.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)