支持在初始化时添加用户

This commit is contained in:
LingZhaoHui 2023-05-27 00:43:42 +08:00
parent 3486bc2b40
commit 556c2f0a08
Signed by: zeekling
GPG Key ID: D96E4E75267CA2CC
2 changed files with 86 additions and 88 deletions

View File

@ -1,43 +1,16 @@
#include <pthread.h> #include <pthread.h>
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include "redis-acl.h" #include "redis-acl.h"
#include "redismodule.h" #include "redismodule.h"
static RedisModuleCommandFilter *filter;
static int times = 1; static int times = 1;
static int MAX_TIME = 1000; static int MAX_TIME = 1000;
static RedisModuleDict *userDict = NULL;
void AuthFilter_CommandFilter(RedisModuleCommandFilter *filter) { RedisModuleUser *createUser(RedisModuleCtx *ctx, const char *name) {
int pos = 0;
RedisModule_Log(NULL, LOG_LEVEL_NOTICE, "command filter");
while (pos < RedisModule_CommandFilterArgsCount(filter)) {
const RedisModuleString *arg = RedisModule_CommandFilterArgGet(filter, pos);
size_t arg_len;
const char *arg_str = RedisModule_StringPtrLen(arg, &arg_len);
// RedisModule_Log(NULL, LOG_LEVEL_NOTICE, "str=%s,len=%ld", arg_str, arg_len);
// if (strcmp(arg_str, "auth") == 0) {
// RedisModule_Log(NULL, LOG_LEVEL_NOTICE, "command is auth");
// RedisModule_CommandFilterArgReplace(filter, pos,
// RedisModule_CreateString(NULL, "acl.auth", 9));
//}
// 解密
pos++;
}
RedisModule_Log(NULL, LOG_LEVEL_NOTICE, "filter finished");
}
int AuthCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
int argc) {
REDISMODULE_NOT_USED(ctx); REDISMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(argc);
REDISMODULE_NOT_USED(argv);
RedisModule_Log(ctx, LOG_LEVEL_NOTICE, "acl.auth begin");
RedisModule_ReplyWithCString(ctx, "ok");
return REDISMODULE_OK;
}
RedisModuleUser* createUser(RedisModuleCtx *ctx, const char *name) {
RedisModuleUser *user = RedisModule_CreateModuleUser(name); RedisModuleUser *user = RedisModule_CreateModuleUser(name);
RedisModule_SetModuleUserACL(user, "allcommands"); RedisModule_SetModuleUserACL(user, "allcommands");
RedisModule_SetModuleUserACL(user, "allkeys"); RedisModule_SetModuleUserACL(user, "allkeys");
@ -45,8 +18,8 @@ RedisModuleUser* createUser(RedisModuleCtx *ctx, const char *name) {
return user; return user;
} }
int module_auth_reply(RedisModuleCtx *ctx, RedisModuleString *username, int authReply(RedisModuleCtx *ctx, RedisModuleString *username, RedisModuleString *password, RedisModuleString **err) {
RedisModuleString *password, RedisModuleString **err) { REDISMODULE_NOT_USED(password);
void **targ = RedisModule_GetBlockedClientPrivateData(ctx); void **targ = RedisModule_GetBlockedClientPrivateData(ctx);
int result = (uintptr_t)targ[0]; int result = (uintptr_t)targ[0];
RedisModule_Log(ctx, LOG_LEVEL_NOTICE, "auth reply"); RedisModule_Log(ctx, LOG_LEVEL_NOTICE, "auth reply");
@ -56,9 +29,10 @@ int module_auth_reply(RedisModuleCtx *ctx, RedisModuleString *username,
// auth success // auth success
RedisModuleUser *moduleUser = createUser(ctx, user); RedisModuleUser *moduleUser = createUser(ctx, user);
uint64_t client_id; uint64_t client_id;
int auth_result = RedisModule_AuthenticateClientWithUser(ctx, moduleUser, NULL, NULL, &client_id); int authResult = RedisModule_AuthenticateClientWithUser(
ctx, moduleUser, NULL, NULL, &client_id);
RedisModule_Log(ctx, LOG_LEVEL_NOTICE, "auth success user=%s, %lu", user, client_id); RedisModule_Log(ctx, LOG_LEVEL_NOTICE, "auth success user=%s, %lu", user, client_id);
if (auth_result == REDISMODULE_ERR) { if (authResult == REDISMODULE_ERR) {
RedisModule_Log(ctx, LOG_LEVEL_NOTICE, "user not exits user=%s", user); RedisModule_Log(ctx, LOG_LEVEL_NOTICE, "user not exits user=%s", user);
} }
return REDISMODULE_AUTH_HANDLED; return REDISMODULE_AUTH_HANDLED;
@ -72,46 +46,46 @@ int module_auth_reply(RedisModuleCtx *ctx, RedisModuleString *username,
return REDISMODULE_AUTH_HANDLED; return REDISMODULE_AUTH_HANDLED;
} }
void free_auth_data(RedisModuleCtx *ctx, void *privdata) { void freeAuthData(RedisModuleCtx *ctx, void *privdata) {
REDISMODULE_NOT_USED(ctx); REDISMODULE_NOT_USED(ctx);
RedisModule_Free(privdata); RedisModule_Free(privdata);
} }
void *AuthBlock_ThreadMain(void *arg) { void *AuthBlockThreadMain(void *arg) {
void **targ = arg; void **targ = arg;
RedisModuleBlockedClient *bc = targ[0]; RedisModuleBlockedClient *bc = targ[0];
RedisModuleCtx *ctx = targ[1]; RedisModuleCtx *ctx = targ[1];
RedisModule_Log(ctx, LOG_LEVEL_NOTICE, "begin auth "); RedisModule_Log(ctx, LOG_LEVEL_NOTICE, "begin auth ");
const char *user = RedisModule_StringPtrLen(targ[2], NULL);
const char *pwd = RedisModule_StringPtrLen(targ[3], NULL); const char *pwd = RedisModule_StringPtrLen(targ[3], NULL);
void **replyarg = RedisModule_Alloc(sizeof(void *));
int result = 2; int result = 2;
if (!strcmp(user, "foo") && !strcmp(pwd, "block_allow")) { int nokey;
RedisModule_Log(ctx, LOG_LEVEL_NOTICE, "auth success"); struct redisAcl *acl = (struct redisAcl *)RedisModule_DictGet(userDict, targ[2], &nokey);
result = 1; if (nokey || !acl) {
} else if (!strcmp(user, "foo") && !strcmp(pwd, "block_deny")) { RedisModule_Log(ctx, LOG_LEVEL_WARNING, "auth failed");
result = 0; result = 0;
} else if (!strcmp(user, "foo") && !strcmp(pwd, "block_abort")) { goto returnResult;
RedisModule_BlockedClientMeasureTimeEnd(bc); }
RedisModule_AbortBlock(bc); if (!strcmp(pwd, acl->password)) {
goto cleanup; result = 1;
} else { } else {
result = 0; result = 0;
} }
void **replyarg = RedisModule_Alloc(sizeof(void *)); returnResult:
replyarg[0] = (void *)(uintptr_t)result; replyarg[0] = (void *)(uintptr_t)result;
RedisModule_BlockedClientMeasureTimeEnd(bc); RedisModule_BlockedClientMeasureTimeEnd(bc);
RedisModule_UnblockClient(bc, replyarg); RedisModule_UnblockClient(bc, replyarg);
cleanup:
RedisModule_FreeString(NULL, targ[2]); RedisModule_FreeString(NULL, targ[2]);
RedisModule_FreeString(NULL, targ[3]); RedisModule_FreeString(NULL, targ[3]);
RedisModule_Free(targ); RedisModule_Free(targ);
return NULL; return NULL;
} }
int module_auth(RedisModuleCtx *ctx, RedisModuleString *username, int moduleBlockAuth(RedisModuleCtx *ctx, RedisModuleString *username, RedisModuleString *password, RedisModuleString **err) {
RedisModuleString *password, RedisModuleString **err) { REDISMODULE_NOT_USED(password);
REDISMODULE_NOT_USED(err);
RedisModuleBlockedClient *bc = RedisModuleBlockedClient *bc =
RedisModule_BlockClientOnAuth(ctx, module_auth_reply, free_auth_data); RedisModule_BlockClientOnAuth(ctx, authReply, freeAuthData);
int ctx_flags = RedisModule_GetContextFlags(ctx); int ctx_flags = RedisModule_GetContextFlags(ctx);
if (ctx_flags & REDISMODULE_CTX_FLAGS_MULTI || if (ctx_flags & REDISMODULE_CTX_FLAGS_MULTI ||
ctx_flags & REDISMODULE_CTX_FLAGS_LUA) { ctx_flags & REDISMODULE_CTX_FLAGS_LUA) {
@ -125,23 +99,32 @@ int module_auth(RedisModuleCtx *ctx, RedisModuleString *username,
targ[1] = ctx; targ[1] = ctx;
targ[2] = RedisModule_CreateStringFromString(NULL, username); targ[2] = RedisModule_CreateStringFromString(NULL, username);
targ[3] = RedisModule_CreateStringFromString(NULL, password); targ[3] = RedisModule_CreateStringFromString(NULL, password);
/* Create bg thread and pass the blockedclient, username and password to it. if (pthread_create(&tid, NULL, AuthBlockThreadMain, targ) != 0) {
*/
if (pthread_create(&tid, NULL, AuthBlock_ThreadMain, targ) != 0) {
RedisModule_AbortBlock(bc); RedisModule_AbortBlock(bc);
} }
return REDISMODULE_AUTH_HANDLED; return REDISMODULE_AUTH_HANDLED;
} }
int auth_cb(RedisModuleCtx *ctx, RedisModuleString *username, int moduleAuth(RedisModuleCtx *ctx, RedisModuleString *username, RedisModuleString *password, RedisModuleString **err) {
RedisModuleString *password, RedisModuleString **err) {
const char *user = RedisModule_StringPtrLen(username, NULL); const char *user = RedisModule_StringPtrLen(username, NULL);
const char *pwd = RedisModule_StringPtrLen(password, NULL); const char *pwd = RedisModule_StringPtrLen(password, NULL);
if (!strcmp(user, "foo") && !strcmp(pwd, "allow")) { int nokey;
RedisModuleUser *user = createUser(ctx, "foo"); struct redisAcl *acl = (struct redisAcl *)RedisModule_DictGet(userDict, username, &nokey);
RedisModule_AuthenticateClientWithACLUser(ctx, "foo", 3, NULL, NULL, NULL); if (!nokey) {
RedisModule_Log(ctx, LOG_LEVEL_NOTICE, "user=%s, password=", acl->username, acl->password);
}
if (!nokey && acl->password && !strcmp(pwd, acl->password)) {
RedisModuleUser *moduleUser = createUser(ctx, user);
uint64_t client_id;
int authResult = RedisModule_AuthenticateClientWithUser(
ctx, moduleUser, NULL, NULL, &client_id);
RedisModule_Log(ctx, LOG_LEVEL_NOTICE, "auth success user=%s, %lu", user, client_id);
if (authResult == REDISMODULE_ERR) {
RedisModule_Log(ctx, LOG_LEVEL_NOTICE, "user not exits user=%s", user);
}
return REDISMODULE_AUTH_HANDLED; return REDISMODULE_AUTH_HANDLED;
} else if (!strcmp(user, "foo") && !strcmp(pwd, "deny")) { } else {
const char *err_msg = "Auth denied by Misc Module."; const char *err_msg = "Auth denied by Misc Module.";
*err = RedisModule_CreateString(ctx, err_msg, strlen(err_msg)); *err = RedisModule_CreateString(ctx, err_msg, strlen(err_msg));
return REDISMODULE_AUTH_HANDLED; return REDISMODULE_AUTH_HANDLED;
@ -149,8 +132,7 @@ int auth_cb(RedisModuleCtx *ctx, RedisModuleString *username,
return REDISMODULE_AUTH_NOT_HANDLED; return REDISMODULE_AUTH_NOT_HANDLED;
} }
void cronLoopCallBack(RedisModuleCtx *ctx, RedisModuleEvent *e, uint64_t sub, void cronLoopCallBack(RedisModuleCtx *ctx, RedisModuleEvent *e, uint64_t sub, void *data) {
void *data) {
REDISMODULE_NOT_USED(e); REDISMODULE_NOT_USED(e);
RedisModuleCronLoop *ei = data; RedisModuleCronLoop *ei = data;
REDISMODULE_NOT_USED(ei); REDISMODULE_NOT_USED(ei);
@ -163,35 +145,36 @@ void cronLoopCallBack(RedisModuleCtx *ctx, RedisModuleEvent *e, uint64_t sub,
times = 0; times = 0;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int initUsers(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
int argc) { REDISMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(argv); REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDISMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx, "redis-auth", 1, REDISMODULE_APIVER_1) == if (userDict == NULL) {
REDISMODULE_ERR) { userDict = RedisModule_CreateDict(ctx);
}
struct redisAcl *acl = RedisModule_Calloc(1, sizeof(struct redisAcl));
acl->username = "foo";
acl->password = "block_allow";
RedisModuleString *key = RedisModule_CreateString(ctx, acl->username, strlen(acl->username));
int result = RedisModule_DictSet(userDict, key, &acl);
if (result == REDISMODULE_OK) {
RedisModule_Log(ctx, LOG_LEVEL_NOTICE, "user add success, username=%s", acl->username);
}
return REDISMODULE_OK;
}
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx, "redis-auth", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) {
RedisModule_Log(ctx, LOG_LEVEL_NOTICE, "init redis-auth failed"); RedisModule_Log(ctx, LOG_LEVEL_NOTICE, "init redis-auth failed");
return REDISMODULE_ERR; return REDISMODULE_ERR;
} }
filter = RedisModule_RegisterCommandFilter(ctx, AuthFilter_CommandFilter, 0); RedisModule_RegisterAuthCallback(ctx, moduleBlockAuth);
if (filter == NULL) { RedisModule_RegisterAuthCallback(ctx, moduleAuth);
RedisModule_Log(ctx, LOG_LEVEL_WARNING, "init filter failed");
return REDISMODULE_ERR;
}
RedisModule_Log(ctx, LOG_LEVEL_NOTICE, "init filter success");
if (RedisModule_CreateCommand(ctx, "acl.auth", AuthCommand_RedisCommand, initUsers(ctx, argv, argc);
"no-auth", 0, 0, 0) == REDISMODULE_ERR) {
RedisModule_Log(ctx, LOG_LEVEL_WARNING, "init acl.auth failed");
return REDISMODULE_ERR;
}
RedisModule_RegisterAuthCallback(ctx, module_auth);
RedisModule_RegisterAuthCallback(ctx, auth_cb);
RedisModule_Log(ctx, LOG_LEVEL_NOTICE, "init command success");
// RedisModule_SubscribeToServerEvent(ctx, RedisModuleEvent_CronLoop,
// cronLoopCallBack);
RedisModule_Log(ctx, LOG_LEVEL_NOTICE, "init redis-auth success!"); RedisModule_Log(ctx, LOG_LEVEL_NOTICE, "init redis-auth success!");
return REDISMODULE_OK; return REDISMODULE_OK;

View File

@ -10,12 +10,27 @@
#define UNUSED(V) ((void) V) #define UNUSED(V) ((void) V)
/* * struct redisAcl {
* Redis Auth command char *username;
* */ char *password;
int AuthCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); } redisAcl;
void AuthFilter_CommandFilter(RedisModuleCommandFilter *filter);
RedisModuleUser *createUser(RedisModuleCtx *ctx, const char *name);
int authReply(RedisModuleCtx *ctx, RedisModuleString *username, RedisModuleString *password, RedisModuleString **err);
void freeAuthData(RedisModuleCtx *ctx, void *privdata);
void *AuthBlockThreadMain(void *arg);
int moduleBlockAuth(RedisModuleCtx *ctx, RedisModuleString *username, RedisModuleString *password, RedisModuleString **err);
int moduleAuth(RedisModuleCtx *ctx, RedisModuleString *username, RedisModuleString *password, RedisModuleString **err);
void cronLoopCallBack(RedisModuleCtx *ctx, RedisModuleEvent *e, uint64_t sub, void *data);
int initUsers(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
#endif // REDISAUTH_H #endif // REDISAUTH_H