diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/modules/aclcheck.c | 55 | ||||
-rw-r--r-- | tests/modules/datatype.c | 29 | ||||
-rw-r--r-- | tests/modules/moduleconfigs.c | 35 | ||||
-rw-r--r-- | tests/unit/moduleapi/aclcheck.tcl | 39 | ||||
-rw-r--r-- | tests/unit/moduleapi/datatype.tcl | 4 | ||||
-rw-r--r-- | tests/unit/moduleapi/moduleconfigs.tcl | 4 |
6 files changed, 166 insertions, 0 deletions
diff --git a/tests/modules/aclcheck.c b/tests/modules/aclcheck.c index 9f4564d27..09b525cc5 100644 --- a/tests/modules/aclcheck.c +++ b/tests/modules/aclcheck.c @@ -183,6 +183,37 @@ int rm_call_aclcheck(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){ return REDISMODULE_OK; } +int module_test_acl_category(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { + REDISMODULE_NOT_USED(argv); + REDISMODULE_NOT_USED(argc); + RedisModule_ReplyWithSimpleString(ctx, "OK"); + return REDISMODULE_OK; +} + +int commandBlockCheck(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { + REDISMODULE_NOT_USED(argv); + REDISMODULE_NOT_USED(argc); + int response_ok = 0; + int result = RedisModule_CreateCommand(ctx,"command.that.should.fail", module_test_acl_category, "", 0, 0, 0); + response_ok |= (result == REDISMODULE_OK); + + RedisModuleCommand *parent = RedisModule_GetCommand(ctx,"block.commands.outside.onload"); + result = RedisModule_SetCommandACLCategories(parent, "write"); + response_ok |= (result == REDISMODULE_OK); + + result = RedisModule_CreateSubcommand(parent,"subcommand.that.should.fail",module_test_acl_category,"",0,0,0); + response_ok |= (result == REDISMODULE_OK); + + /* This validates that it's not possible to create commands outside OnLoad, + * thus returns an error if they succeed. */ + if (response_ok) { + RedisModule_ReplyWithError(ctx, "UNEXPECTEDOK"); + } else { + RedisModule_ReplyWithSimpleString(ctx, "OK"); + } + return REDISMODULE_OK; +} + int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { REDISMODULE_NOT_USED(argv); REDISMODULE_NOT_USED(argc); @@ -193,6 +224,30 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) if (RedisModule_CreateCommand(ctx,"aclcheck.set.check.key", set_aclcheck_key,"write",0,0,0) == REDISMODULE_ERR) return REDISMODULE_ERR; + if (RedisModule_CreateCommand(ctx,"block.commands.outside.onload", commandBlockCheck,"write",0,0,0) == REDISMODULE_ERR) + return REDISMODULE_ERR; + + if (RedisModule_CreateCommand(ctx,"aclcheck.module.command.aclcategories.write", module_test_acl_category,"write",0,0,0) == REDISMODULE_ERR) + return REDISMODULE_ERR; + RedisModuleCommand *aclcategories_write = RedisModule_GetCommand(ctx,"aclcheck.module.command.aclcategories.write"); + + if (RedisModule_SetCommandACLCategories(aclcategories_write, "write") == REDISMODULE_ERR) + return REDISMODULE_ERR; + + if (RedisModule_CreateCommand(ctx,"aclcheck.module.command.aclcategories.write.function.read.category", module_test_acl_category,"write",0,0,0) == REDISMODULE_ERR) + return REDISMODULE_ERR; + RedisModuleCommand *read_category = RedisModule_GetCommand(ctx,"aclcheck.module.command.aclcategories.write.function.read.category"); + + if (RedisModule_SetCommandACLCategories(read_category, "read") == REDISMODULE_ERR) + return REDISMODULE_ERR; + + if (RedisModule_CreateCommand(ctx,"aclcheck.module.command.aclcategories.read.only.category", module_test_acl_category,"",0,0,0) == REDISMODULE_ERR) + return REDISMODULE_ERR; + RedisModuleCommand *read_only_category = RedisModule_GetCommand(ctx,"aclcheck.module.command.aclcategories.read.only.category"); + + if (RedisModule_SetCommandACLCategories(read_only_category, "read") == REDISMODULE_ERR) + return REDISMODULE_ERR; + if (RedisModule_CreateCommand(ctx,"aclcheck.publish.check.channel", publish_aclcheck_channel,"",0,0,0) == REDISMODULE_ERR) return REDISMODULE_ERR; diff --git a/tests/modules/datatype.c b/tests/modules/datatype.c index 45a356e52..408d1a526 100644 --- a/tests/modules/datatype.c +++ b/tests/modules/datatype.c @@ -234,6 +234,31 @@ static int datatype_is_in_slow_loading(RedisModuleCtx *ctx, RedisModuleString ** return REDISMODULE_OK; } +int createDataTypeBlockCheck(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { + REDISMODULE_NOT_USED(argv); + REDISMODULE_NOT_USED(argc); + static RedisModuleType *datatype_outside_onload = NULL; + + RedisModuleTypeMethods datatype_methods = { + .version = REDISMODULE_TYPE_METHOD_VERSION, + .rdb_load = datatype_load, + .rdb_save = datatype_save, + .free = datatype_free, + .copy = datatype_copy + }; + + datatype_outside_onload = RedisModule_CreateDataType(ctx, "test_dt_outside_onload", 1, &datatype_methods); + + /* This validates that it's not possible to create datatype outside OnLoad, + * thus returns an error if it succeeds. */ + if (datatype_outside_onload == NULL) { + RedisModule_ReplyWithSimpleString(ctx, "OK"); + } else { + RedisModule_ReplyWithError(ctx, "UNEXPECTEDOK"); + } + return REDISMODULE_OK; +} + int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { REDISMODULE_NOT_USED(argv); REDISMODULE_NOT_USED(argc); @@ -241,6 +266,10 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) if (RedisModule_Init(ctx,"datatype",DATATYPE_ENC_VER,REDISMODULE_APIVER_1) == REDISMODULE_ERR) return REDISMODULE_ERR; + /* Creates a command which creates a datatype outside OnLoad() function. */ + if (RedisModule_CreateCommand(ctx,"block.create.datatype.outside.onload", createDataTypeBlockCheck, "write", 0, 0, 0) == REDISMODULE_ERR) + return REDISMODULE_ERR; + RedisModule_SetModuleOptions(ctx, REDISMODULE_OPTIONS_HANDLE_IO_ERRORS); RedisModuleTypeMethods datatype_methods = { diff --git a/tests/modules/moduleconfigs.c b/tests/modules/moduleconfigs.c index b48133372..2c1737df7 100644 --- a/tests/modules/moduleconfigs.c +++ b/tests/modules/moduleconfigs.c @@ -103,6 +103,37 @@ int longlongApplyFunc(RedisModuleCtx *ctx, void *privdata, RedisModuleString **e return REDISMODULE_OK; } +int registerBlockCheck(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { + REDISMODULE_NOT_USED(argv); + REDISMODULE_NOT_USED(argc); + int response_ok = 0; + int result = RedisModule_RegisterBoolConfig(ctx, "mutable_bool", 1, REDISMODULE_CONFIG_DEFAULT, getBoolConfigCommand, setBoolConfigCommand, boolApplyFunc, &mutable_bool_val); + response_ok |= (result == REDISMODULE_OK); + + result = RedisModule_RegisterStringConfig(ctx, "string", "secret password", REDISMODULE_CONFIG_DEFAULT, getStringConfigCommand, setStringConfigCommand, NULL, NULL); + response_ok |= (result == REDISMODULE_OK); + + const char *enum_vals[] = {"none", "five", "one", "two", "four"}; + const int int_vals[] = {0, 5, 1, 2, 4}; + result = RedisModule_RegisterEnumConfig(ctx, "enum", 1, REDISMODULE_CONFIG_DEFAULT, enum_vals, int_vals, 5, getEnumConfigCommand, setEnumConfigCommand, NULL, NULL); + response_ok |= (result == REDISMODULE_OK); + + result = RedisModule_RegisterNumericConfig(ctx, "numeric", -1, REDISMODULE_CONFIG_DEFAULT, -5, 2000, getNumericConfigCommand, setNumericConfigCommand, longlongApplyFunc, &longval); + response_ok |= (result == REDISMODULE_OK); + + result = RedisModule_LoadConfigs(ctx); + response_ok |= (result == REDISMODULE_OK); + + /* This validates that it's not possible to register/load configs outside OnLoad, + * thus returns an error if they succeed. */ + if (response_ok) { + RedisModule_ReplyWithError(ctx, "UNEXPECTEDOK"); + } else { + RedisModule_ReplyWithSimpleString(ctx, "OK"); + } + return REDISMODULE_OK; +} + int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { REDISMODULE_NOT_USED(argv); REDISMODULE_NOT_USED(argc); @@ -147,6 +178,10 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) } return REDISMODULE_ERR; } + /* Creates a command which registers configs outside OnLoad() function. */ + if (RedisModule_CreateCommand(ctx,"block.register.configs.outside.onload", registerBlockCheck, "write", 0, 0, 0) == REDISMODULE_ERR) + return REDISMODULE_ERR; + return REDISMODULE_OK; } diff --git a/tests/unit/moduleapi/aclcheck.tcl b/tests/unit/moduleapi/aclcheck.tcl index 5dae6e1ad..ae3f67156 100644 --- a/tests/unit/moduleapi/aclcheck.tcl +++ b/tests/unit/moduleapi/aclcheck.tcl @@ -92,6 +92,45 @@ start_server {tags {"modules acl"}} { assert {[dict get $entry reason] eq {command}} } + test {test blocking of Commands outside of OnLoad} { + assert_equal [r block.commands.outside.onload] OK + } + + test {test users to have access to module commands having acl categories} { + r acl SETUSER j1 on >password -@all +@WRITE + r acl SETUSER j2 on >password -@all +@READ + assert_equal [r acl DRYRUN j1 aclcheck.module.command.aclcategories.write] OK + assert_equal [r acl DRYRUN j2 aclcheck.module.command.aclcategories.write.function.read.category] OK + assert_equal [r acl DRYRUN j2 aclcheck.module.command.aclcategories.read.only.category] OK + } + + test {test existing users to have access to module commands loaded on runtime} { + assert_equal [r module unload aclcheck] OK + r acl SETUSER j3 on >password -@all +@WRITE + assert_equal [r module load $testmodule] OK + assert_equal [r acl DRYRUN j3 aclcheck.module.command.aclcategories.write] OK + } + + test {test existing users without permissions, do not have access to module commands loaded on runtime.} { + assert_equal [r module unload aclcheck] OK + r acl SETUSER j4 on >password -@all +@READ + r acl SETUSER j5 on >password -@all +@WRITE + assert_equal [r module load $testmodule] OK + catch {r acl DRYRUN j4 aclcheck.module.command.aclcategories.write} e + assert_equal {User j4 has no permissions to run the 'aclcheck.module.command.aclcategories.write' command} $e + catch {r acl DRYRUN j5 aclcheck.module.command.aclcategories.write.function.read.category} e + assert_equal {User j5 has no permissions to run the 'aclcheck.module.command.aclcategories.write.function.read.category' command} $e + } + + test {test users without permissions, do not have access to module commands.} { + r acl SETUSER j6 on >password -@all +@READ + catch {r acl DRYRUN j6 aclcheck.module.command.aclcategories.write} e + assert_equal {User j6 has no permissions to run the 'aclcheck.module.command.aclcategories.write' command} $e + r acl SETUSER j7 on >password -@all +@WRITE + catch {r acl DRYRUN j7 aclcheck.module.command.aclcategories.write.function.read.category} e + assert_equal {User j7 has no permissions to run the 'aclcheck.module.command.aclcategories.write.function.read.category' command} $e + } + test "Unload the module - aclcheck" { assert_equal {OK} [r module unload aclcheck] } diff --git a/tests/unit/moduleapi/datatype.tcl b/tests/unit/moduleapi/datatype.tcl index c8fd30ed1..0c87e9597 100644 --- a/tests/unit/moduleapi/datatype.tcl +++ b/tests/unit/moduleapi/datatype.tcl @@ -8,6 +8,10 @@ start_server {tags {"modules"}} { assert {[r datatype.get dtkey] eq {100 stringval}} } + test {test blocking of datatype creation outside of OnLoad} { + assert_equal [r block.create.datatype.outside.onload] OK + } + test {DataType: RM_SaveDataTypeToString(), RM_LoadDataTypeFromStringEncver() work} { r datatype.set dtkey -1111 MyString set encoded [r datatype.dump dtkey] diff --git a/tests/unit/moduleapi/moduleconfigs.tcl b/tests/unit/moduleapi/moduleconfigs.tcl index 2b28fc307..1709e9d99 100644 --- a/tests/unit/moduleapi/moduleconfigs.tcl +++ b/tests/unit/moduleapi/moduleconfigs.tcl @@ -77,6 +77,10 @@ start_server {tags {"modules"}} { assert_match {*must be one of the following*} $e } + test {test blocking of config registration and load outside of OnLoad} { + assert_equal [r block.register.configs.outside.onload] OK + } + test {Unload removes module configs} { r module unload moduleconfigs assert_equal [r config get moduleconfigs.*] "" |