Unverified Commit 416c9ac2 authored by Madelyn Olson's avatar Madelyn Olson Committed by GitHub
Browse files

Add module API for redacting command arguments (#10425)

Add module API for redacting client commands
parent c30de707
......@@ -8611,6 +8611,24 @@ int RM_DeauthenticateAndCloseClient(RedisModuleCtx *ctx, uint64_t client_id) {
return REDISMODULE_OK;
}
/* Redact the client command argument specified at the given position. Redacted arguments
* are obfuscated in user facing commands such as SLOWLOG or MONITOR, as well as
* never being written to server logs. This command may be called multiple times on the
* same position.
*
* Note that the command name, position 0, can not be redacted.
*
* Returns REDISMODULE_OK if the argument was redacted and REDISMODULE_ERR if there
* was an invalid parameter passed in or the position is outside the client
* argument range. */
int RM_RedactClientCommandArgument(RedisModuleCtx *ctx, int pos) {
if (!ctx || !ctx->client || pos <= 0 || ctx->client->argc <= pos) {
return REDISMODULE_ERR;
}
redactClientCommandArgument(ctx->client, pos);
return REDISMODULE_OK;
}
/* Return the X.509 client-side certificate used by the client to authenticate
* this connection.
*
......@@ -11808,6 +11826,7 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API(IsSubEventSupported);
REGISTER_API(GetServerVersion);
REGISTER_API(GetClientCertificate);
REGISTER_API(RedactClientCommandArgument);
REGISTER_API(GetCommandKeys);
REGISTER_API(GetCommandKeysWithFlags);
REGISTER_API(GetCurrentCommandName);
......
......@@ -3471,7 +3471,11 @@ static void retainOriginalCommandVector(client *c) {
* original_argv array. */
void redactClientCommandArgument(client *c, int argc) {
retainOriginalCommandVector(c);
decrRefCount(c->argv[argc]);
if (c->original_argv[argc] == shared.redacted) {
/* This argument has already been redacted */
return;
}
decrRefCount(c->original_argv[argc]);
c->original_argv[argc] = shared.redacted;
}
......
......@@ -1143,6 +1143,7 @@ REDISMODULE_API void (*RedisModule_ACLAddLogEntry)(RedisModuleCtx *ctx, RedisMod
REDISMODULE_API int (*RedisModule_AuthenticateClientWithACLUser)(RedisModuleCtx *ctx, const char *name, size_t len, RedisModuleUserChangedFunc callback, void *privdata, uint64_t *client_id) REDISMODULE_ATTR;
REDISMODULE_API int (*RedisModule_AuthenticateClientWithUser)(RedisModuleCtx *ctx, RedisModuleUser *user, RedisModuleUserChangedFunc callback, void *privdata, uint64_t *client_id) REDISMODULE_ATTR;
REDISMODULE_API int (*RedisModule_DeauthenticateAndCloseClient)(RedisModuleCtx *ctx, uint64_t client_id) REDISMODULE_ATTR;
REDISMODULE_API int (*RedisModule_RedactClientCommandArgument)(RedisModuleCtx *ctx, int pos) REDISMODULE_ATTR;
REDISMODULE_API RedisModuleString * (*RedisModule_GetClientCertificate)(RedisModuleCtx *ctx, uint64_t id) REDISMODULE_ATTR;
REDISMODULE_API int *(*RedisModule_GetCommandKeys)(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int *num_keys) REDISMODULE_ATTR;
REDISMODULE_API int *(*RedisModule_GetCommandKeysWithFlags)(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int *num_keys, int **out_flags) REDISMODULE_ATTR;
......@@ -1466,6 +1467,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API(DeauthenticateAndCloseClient);
REDISMODULE_GET_API(AuthenticateClientWithACLUser);
REDISMODULE_GET_API(AuthenticateClientWithUser);
REDISMODULE_GET_API(RedactClientCommandArgument);
REDISMODULE_GET_API(GetClientCertificate);
REDISMODULE_GET_API(GetCommandKeys);
REDISMODULE_GET_API(GetCommandKeysWithFlags);
......
......@@ -54,6 +54,16 @@ int Auth_AuthRealUser(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
return RedisModule_ReplyWithLongLong(ctx, (uint64_t) client_id);
}
/* This command redacts every other arguments and returns OK */
int Auth_RedactedAPI(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
for(int i = argc - 1; i > 0; i -= 2) {
int result = RedisModule_RedactClientCommandArgument(ctx, i);
RedisModule_Assert(result == REDISMODULE_OK);
}
return RedisModule_ReplyWithSimpleString(ctx, "OK");
}
int Auth_ChangeCount(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
......@@ -87,6 +97,10 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
Auth_ChangeCount,"",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"auth.redact",
Auth_RedactedAPI,"",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
return REDISMODULE_OK;
}
......
......@@ -68,6 +68,22 @@ start_server {tags {"modules"}} {
assert_equal [r acl whoami] "default"
}
test {modules can redact arguments} {
r config set slowlog-log-slower-than 0
r slowlog reset
r auth.redact 1 2 3 4
r auth.redact 1 2 3
r config set slowlog-log-slower-than 10000
set slowlog_resp [r slowlog get]
# There will be 3 records, slowlog reset and the
# two auth redact calls.
assert_equal 3 [llength $slowlog_resp]
assert_equal {slowlog reset} [lindex [lindex [r slowlog get] 2] 3]
assert_equal {auth.redact 1 (redacted) 3 (redacted)} [lindex [lindex [r slowlog get] 1] 3]
assert_equal {auth.redact (redacted) 2 (redacted)} [lindex [lindex [r slowlog get] 0] 3]
}
test "Unload the module - testacl" {
assert_equal {OK} [r module unload testacl]
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment