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) { ...@@ -8611,6 +8611,24 @@ int RM_DeauthenticateAndCloseClient(RedisModuleCtx *ctx, uint64_t client_id) {
return REDISMODULE_OK; 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 /* Return the X.509 client-side certificate used by the client to authenticate
* this connection. * this connection.
* *
...@@ -11808,6 +11826,7 @@ void moduleRegisterCoreAPI(void) { ...@@ -11808,6 +11826,7 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API(IsSubEventSupported); REGISTER_API(IsSubEventSupported);
REGISTER_API(GetServerVersion); REGISTER_API(GetServerVersion);
REGISTER_API(GetClientCertificate); REGISTER_API(GetClientCertificate);
REGISTER_API(RedactClientCommandArgument);
REGISTER_API(GetCommandKeys); REGISTER_API(GetCommandKeys);
REGISTER_API(GetCommandKeysWithFlags); REGISTER_API(GetCommandKeysWithFlags);
REGISTER_API(GetCurrentCommandName); REGISTER_API(GetCurrentCommandName);
......
...@@ -3471,7 +3471,11 @@ static void retainOriginalCommandVector(client *c) { ...@@ -3471,7 +3471,11 @@ static void retainOriginalCommandVector(client *c) {
* original_argv array. */ * original_argv array. */
void redactClientCommandArgument(client *c, int argc) { void redactClientCommandArgument(client *c, int argc) {
retainOriginalCommandVector(c); 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; c->original_argv[argc] = shared.redacted;
} }
......
...@@ -1143,6 +1143,7 @@ REDISMODULE_API void (*RedisModule_ACLAddLogEntry)(RedisModuleCtx *ctx, RedisMod ...@@ -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_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_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_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 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_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; 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 ...@@ -1466,6 +1467,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API(DeauthenticateAndCloseClient); REDISMODULE_GET_API(DeauthenticateAndCloseClient);
REDISMODULE_GET_API(AuthenticateClientWithACLUser); REDISMODULE_GET_API(AuthenticateClientWithACLUser);
REDISMODULE_GET_API(AuthenticateClientWithUser); REDISMODULE_GET_API(AuthenticateClientWithUser);
REDISMODULE_GET_API(RedactClientCommandArgument);
REDISMODULE_GET_API(GetClientCertificate); REDISMODULE_GET_API(GetClientCertificate);
REDISMODULE_GET_API(GetCommandKeys); REDISMODULE_GET_API(GetCommandKeys);
REDISMODULE_GET_API(GetCommandKeysWithFlags); REDISMODULE_GET_API(GetCommandKeysWithFlags);
......
...@@ -54,6 +54,16 @@ int Auth_AuthRealUser(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { ...@@ -54,6 +54,16 @@ int Auth_AuthRealUser(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
return RedisModule_ReplyWithLongLong(ctx, (uint64_t) client_id); 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) { int Auth_ChangeCount(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDISMODULE_NOT_USED(argc);
...@@ -87,6 +97,10 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) ...@@ -87,6 +97,10 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
Auth_ChangeCount,"",0,0,0) == REDISMODULE_ERR) Auth_ChangeCount,"",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR; return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"auth.redact",
Auth_RedactedAPI,"",0,0,0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
return REDISMODULE_OK; return REDISMODULE_OK;
} }
......
...@@ -68,6 +68,22 @@ start_server {tags {"modules"}} { ...@@ -68,6 +68,22 @@ start_server {tags {"modules"}} {
assert_equal [r acl whoami] "default" 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" { test "Unload the module - testacl" {
assert_equal {OK} [r module unload 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