mirror of
https://codeberg.org/redict/redict.git
synced 2025-01-22 16:18:28 -05:00
233abbbe03
* Make it clear that current_client is the root client that was called by external connection * add executing_client which is the client that runs the current command (can be a module or a script) * Remove script_caller that was used for commands that have CLIENT_SCRIPT to get the client that called the script. in most cases, that's the current_client, and in others (when being called from a module), it could be an intermediate client when we actually want the original one used by the external connection. bugfixes: * RM_Call with C flag should log ACL errors with the requested user rather than the one used by the original client, this also solves a crash when RM_Call is used with C flag from a detached thread safe context. * addACLLogEntry would have logged info about the script_caller, but in case the script was issued by a module command we actually want the current_client. the exception is when RM_Call is called from a timer event, in which case we don't have a current_client. behavior changes: * client side tracking for scripts now tracks the keys that are read by the script instead of the keys that are declared by the caller for EVAL other changes: * Log both current_client and executing_client in the crash log. * remove prepareLuaClient and resetLuaClient, being dead code that was forgotten. * remove scriptTimeSnapshot and snapshot_time and instead add cmd_time_snapshot that serves all commands and is reset only when execution nesting starts. * remove code to propagate CLIENT_FORCE_REPL from the executed command to the script caller since scripts aren't propagated anyway these days and anyway this flag wouldn't have had an effect since CLIENT_PREVENT_PROP is added by scriptResetRun. * fix a module GIL violation issue in afterSleep that was introduced in #10300 (unreleased)
137 lines
5.7 KiB
Tcl
137 lines
5.7 KiB
Tcl
set testmodule [file normalize tests/modules/usercall.so]
|
|
|
|
set test_script_set "#!lua
|
|
redis.call('set','x',1)
|
|
return 1"
|
|
|
|
set test_script_get "#!lua
|
|
redis.call('get','x')
|
|
return 1"
|
|
|
|
start_server {tags {"modules usercall"}} {
|
|
r module load $testmodule
|
|
|
|
# baseline test that module isn't doing anything weird
|
|
test {test module check regular redis command without user/acl} {
|
|
assert_equal [r usercall.reset_user] OK
|
|
assert_equal [r usercall.add_to_acl "~* &* +@all -set"] OK
|
|
assert_equal [r usercall.call_without_user set x 5] OK
|
|
assert_equal [r usercall.reset_user] OK
|
|
}
|
|
|
|
# call with user with acl set on it, but without testing the acl
|
|
test {test module check regular redis command with user} {
|
|
assert_equal [r set x 5] OK
|
|
|
|
assert_equal [r usercall.reset_user] OK
|
|
assert_equal [r usercall.add_to_acl "~* &* +@all -set"] OK
|
|
# off and sanitize-payload because module user / default value
|
|
assert_equal [r usercall.get_acl] "off sanitize-payload ~* &* +@all -set"
|
|
|
|
# doesn't fail for regular commands as just testing acl here
|
|
assert_equal [r usercall.call_with_user_flag {} set x 10] OK
|
|
|
|
assert_equal [r get x] 10
|
|
assert_equal [r usercall.reset_user] OK
|
|
}
|
|
|
|
# call with user with acl set on it, but with testing the acl in rm_call (for cmd itself)
|
|
test {test module check regular redis command with user and acl} {
|
|
assert_equal [r set x 5] OK
|
|
|
|
r ACL LOG RESET
|
|
assert_equal [r usercall.reset_user] OK
|
|
assert_equal [r usercall.add_to_acl "~* &* +@all -set"] OK
|
|
# off and sanitize-payload because module user / default value
|
|
assert_equal [r usercall.get_acl] "off sanitize-payload ~* &* +@all -set"
|
|
|
|
# fails here as testing acl in rm call
|
|
assert_error {*NOPERM User module_user has no permissions*} {r usercall.call_with_user_flag C set x 10}
|
|
|
|
assert_equal [r usercall.call_with_user_flag C get x] 5
|
|
|
|
# verify that new log entry added
|
|
set entry [lindex [r ACL LOG] 0]
|
|
assert_equal [dict get $entry username] {module_user}
|
|
assert_equal [dict get $entry context] {module}
|
|
assert_equal [dict get $entry object] {set}
|
|
assert_equal [dict get $entry reason] {command}
|
|
assert_match {*cmd=usercall.call_with_user_flag*} [dict get $entry client-info]
|
|
|
|
assert_equal [r usercall.reset_user] OK
|
|
}
|
|
|
|
# call with user with acl set on it, but with testing the acl in rm_call (for cmd itself)
|
|
test {test module check regular redis command with user and acl from blocked background thread} {
|
|
assert_equal [r set x 5] OK
|
|
|
|
r ACL LOG RESET
|
|
assert_equal [r usercall.reset_user] OK
|
|
assert_equal [r usercall.add_to_acl "~* &* +@all -set"] OK
|
|
|
|
# fails here as testing acl in rm call from a background thread
|
|
assert_error {*NOPERM User module_user has no permissions*} {r usercall.call_with_user_bg C set x 10}
|
|
|
|
assert_equal [r usercall.call_with_user_bg C get x] 5
|
|
|
|
# verify that new log entry added
|
|
set entry [lindex [r ACL LOG] 0]
|
|
assert_equal [dict get $entry username] {module_user}
|
|
assert_equal [dict get $entry context] {module}
|
|
assert_equal [dict get $entry object] {set}
|
|
assert_equal [dict get $entry reason] {command}
|
|
assert_match {*cmd=NULL*} [dict get $entry client-info]
|
|
|
|
assert_equal [r usercall.reset_user] OK
|
|
}
|
|
|
|
# baseline script test, call without user on script
|
|
test {test module check eval script without user} {
|
|
set sha_set [r script load $test_script_set]
|
|
set sha_get [r script load $test_script_get]
|
|
|
|
assert_equal [r usercall.call_without_user evalsha $sha_set 0] 1
|
|
assert_equal [r usercall.call_without_user evalsha $sha_get 0] 1
|
|
}
|
|
|
|
# baseline script test, call without user on script
|
|
test {test module check eval script with user being set, but not acl testing} {
|
|
set sha_set [r script load $test_script_set]
|
|
set sha_get [r script load $test_script_get]
|
|
|
|
assert_equal [r usercall.reset_user] OK
|
|
assert_equal [r usercall.add_to_acl "~* &* +@all -set"] OK
|
|
# off and sanitize-payload because module user / default value
|
|
assert_equal [r usercall.get_acl] "off sanitize-payload ~* &* +@all -set"
|
|
|
|
# passes as not checking ACL
|
|
assert_equal [r usercall.call_with_user_flag {} evalsha $sha_set 0] 1
|
|
assert_equal [r usercall.call_with_user_flag {} evalsha $sha_get 0] 1
|
|
}
|
|
|
|
# call with user on script (without rm_call acl check) to ensure user carries through to script execution
|
|
# we already tested the check in rm_call above, here we are checking the script itself will enforce ACL
|
|
test {test module check eval script with user and acl} {
|
|
set sha_set [r script load $test_script_set]
|
|
set sha_get [r script load $test_script_get]
|
|
|
|
r ACL LOG RESET
|
|
assert_equal [r usercall.reset_user] OK
|
|
assert_equal [r usercall.add_to_acl "~* &* +@all -set"] OK
|
|
|
|
# fails here in script, as rm_call will permit the eval call
|
|
catch {r usercall.call_with_user_flag C evalsha $sha_set 0} e
|
|
assert_match {*ERR ACL failure in script*} $e
|
|
|
|
assert_equal [r usercall.call_with_user_flag C evalsha $sha_get 0] 1
|
|
|
|
# verify that new log entry added
|
|
set entry [lindex [r ACL LOG] 0]
|
|
assert_equal [dict get $entry username] {module_user}
|
|
assert_equal [dict get $entry context] {lua}
|
|
assert_equal [dict get $entry object] {set}
|
|
assert_equal [dict get $entry reason] {command}
|
|
assert_match {*cmd=usercall.call_with_user_flag*} [dict get $entry client-info]
|
|
}
|
|
}
|