Merge pull request '阅读acl对应的源码' (#5) from dev into master

Reviewed-on: zeekling/redis#5
This commit is contained in:
LingZhaoHui 2020-11-26 15:05:30 +00:00
commit 6d671f58e0
5 changed files with 68 additions and 27 deletions

View File

@ -759,7 +759,7 @@ acllog-max-len 128
# The format of the external ACL user file is exactly the same as the
# format that is used inside redis.conf to describe users.
#
# aclfile /etc/redis/users.acl
aclfile /tmp/users.acl
# IMPORTANT NOTE: starting with Redis 6 "requirepass" is just a compatiblity
# layer on top of the new ACL system. The option effect will be just setting

View File

@ -148,7 +148,9 @@ int time_independent_strcmp(char *a, char *b) {
}
/* Given an SDS string, returns the SHA256 hex representation as a
* new SDS string. */
* new SDS string.
*
* * */
sds ACLHashPassword(unsigned char *cleartext, size_t len) {
SHA256_CTX ctx;
unsigned char hash[SHA256_BLOCK_SIZE];
@ -232,7 +234,10 @@ void *ACLListDupSds(void *item) {
* of users (the Users global radix tree), and returns a reference to
* the structure representing the user.
*
* If the user with such name already exists NULL is returned. */
* If the user with such name already exists NULL is returned.
*
*
* */
user *ACLCreateUser(const char *name, size_t namelen) {
if (raxFind(Users,(unsigned char*)name,namelen) != raxNotFound) return NULL;
user *u = zmalloc(sizeof(*u));
@ -255,7 +260,9 @@ user *ACLCreateUser(const char *name, size_t namelen) {
/* This function should be called when we need an unlinked "fake" user
* we can use in order to validate ACL rules or for other similar reasons.
* The user will not get linked to the Users radix tree. The returned
* user should be released with ACLFreeUser() as usually. */
* user should be released with ACLFreeUser() as usually.
*
* * */
user *ACLCreateUnlinkedUser(void) {
char username[64];
for (int j = 0; ; j++) {
@ -354,9 +361,13 @@ int ACLGetCommandBitCoordinates(uint64_t id, uint64_t *word, uint64_t *bit) {
* but just the lowlevel bitmask.
*
* If the bit overflows the user internal representation, zero is returned
* in order to disallow the execution of the command in such edge case. */
* in order to disallow the execution of the command in such edge case.
*
* command对应的bit位
* * */
int ACLGetUserCommandBit(user *u, unsigned long id) {
uint64_t word, bit;
// 计算命令在allowed_commands当中对应的bit位
if (ACLGetCommandBitCoordinates(id,&word,&bit) == C_ERR) return 0;
return (u->allowed_commands[word] & bit) != 0;
}
@ -927,18 +938,22 @@ char *ACLSetUserStringError(void) {
}
/* Initialize the default user, that will always exist for all the process
* lifetime. */
* lifetime.
*
* */
void ACLInitDefaultUser(void) {
DefaultUser = ACLCreateUser("default",7);
ACLSetUser(DefaultUser,"+@all",-1);
ACLSetUser(DefaultUser,"~*",-1);
ACLSetUser(DefaultUser,"on",-1);
ACLSetUser(DefaultUser,"nopass",-1);
ACLSetUser(DefaultUser,"+@all",-1); // 默认用户赋予所有命令的权限
ACLSetUser(DefaultUser,"~*",-1); // 可以操作任何key
ACLSetUser(DefaultUser,"on",-1); // 默认开启
ACLSetUser(DefaultUser,"nopass",-1);// 默认不需要密码
}
/* Initialization of the ACL subsystem. */
/* Initialization of the ACL subsystem.
* ACL子系统
* */
void ACLInit(void) {
Users = raxNew();
Users = raxNew(); // 初始化用户信息
UsersToLoad = listCreate();
ACLLog = listCreate();
ACLInitDefaultUser();
@ -1056,7 +1071,9 @@ user *ACLGetUserByName(const char *name, size_t namelen) {
* ACL_DENIED_CMD or ACL_DENIED_KEY is returned: the first in case the
* command cannot be executed because the user is not allowed to run such
* command, the second if the command is denied because the user is trying
* to access keys that are not among the specified patterns. */
* to access keys that are not among the specified patterns.
*
* * */
int ACLCheckCommandPerm(client *c, int *keyidxptr) {
user *u = c->user;
uint64_t id = c->cmd->id;
@ -1069,7 +1086,9 @@ int ACLCheckCommandPerm(client *c, int *keyidxptr) {
c->cmd->proc != authCommand)
{
/* If the bit is not set we have to check further, in case the
* command is allowed just with that specific subcommand. */
* command is allowed just with that specific subcommand.
*
* */
if (ACLGetUserCommandBit(u,id) == 0) {
/* Check if the subcommand matches. */
if (c->argc < 2 ||
@ -1151,7 +1170,9 @@ int ACLCheckCommandPerm(client *c, int *keyidxptr) {
*
* When an error is detected and C_ERR is returned, the function populates
* by reference (if not set to NULL) the argc_err argument with the index
* of the argv vector that caused the error. */
* of the argv vector that caused the error.
* user配置的ACL信息
* * * */
int ACLAppendUserForLoading(sds *argv, int argc, int *argc_err) {
if (argc < 2 || strcasecmp(argv[0],"user")) {
if (argc_err) *argc_err = 0;
@ -1183,7 +1204,9 @@ int ACLAppendUserForLoading(sds *argv, int argc, int *argc_err) {
/* This function will load the configured users appended to the server
* configuration via ACLAppendUserForLoading(). On loading errors it will
* log an error and return C_ERR, otherwise C_OK will be returned. */
* log an error and return C_ERR, otherwise C_OK will be returned.
* user配置项中读取ACl信息
* * */
int ACLLoadConfiguredUsers(void) {
listIter li;
listNode *ln;
@ -1192,11 +1215,12 @@ int ACLLoadConfiguredUsers(void) {
sds *aclrules = listNodeValue(ln);
sds username = aclrules[0];
// 检查ACL用户名当中是否存在空格
if (ACLStringHasSpaces(aclrules[0],sdslen(aclrules[0]))) {
serverLog(LL_WARNING,"Spaces not allowed in ACL usernames");
return C_ERR;
}
// 创建ACL用户
user *u = ACLCreateUser(username,sdslen(username));
if (!u) {
u = ACLGetUserByName(username,sdslen(username));
@ -1206,6 +1230,7 @@ int ACLLoadConfiguredUsers(void) {
/* Load every rule defined for this user. */
for (int j = 1; aclrules[j]; j++) {
// 添加当前用户的所有属性
if (ACLSetUser(u,aclrules[j],sdslen(aclrules[j])) != C_OK) {
char *errmsg = ACLSetUserStringError();
serverLog(LL_WARNING,"Error loading ACL rule '%s' for "
@ -1216,7 +1241,9 @@ int ACLLoadConfiguredUsers(void) {
}
/* Having a disabled user in the configuration may be an error,
* warn about it without returning any error to the caller. */
* warn about it without returning any error to the caller.
*
* */
if (u->flags & USER_FLAG_DISABLED) {
serverLog(LL_NOTICE, "The user '%s' is disabled (there is no "
"'on' modifier in the user description). Make "
@ -1249,7 +1276,10 @@ int ACLLoadConfiguredUsers(void) {
*
* At the end of the process, if no errors were found in the whole file then
* NULL is returned. Otherwise an SDS string describing in a single line
* a description of all the issues found is returned. */
* a description of all the issues found is returned.
*
* aclfile配置的文件里面读取ACL信息
* */
sds ACLLoadFromFile(const char *filename) {
FILE *fp;
char buf[1024];
@ -1466,7 +1496,9 @@ cleanup:
* loaded, and we are ready to start, in order to load the ACLs either from
* the pending list of users defined in redis.conf, or from the ACL file.
* The function will just exit with an error if the user is trying to mix
* both the loading methods. */
* both the loading methods.
* redis.conf配置项aclfile对应文件里面的ACL权限信息
* */
void ACLLoadUsersAtStartup(void) {
if (server.acl_filename[0] != '\0' && listLength(UsersToLoad) != 0) {
serverLog(LL_WARNING,
@ -1477,7 +1509,7 @@ void ACLLoadUsersAtStartup(void) {
"directly in your redis.conf, but not both.");
exit(1);
}
// 加载user配置的ACL信息
if (ACLLoadConfiguredUsers() == C_ERR) {
serverLog(LL_WARNING,
"Critical error while loading ACLs. Exiting.");

View File

@ -1872,7 +1872,9 @@ void processInputBuffer(client *c) {
break;
}
/* We are finally ready to execute the command. */
/* We are finally ready to execute the command.
*
* */
if (processCommandAndResetClient(c) == C_ERR) {
/* If the client is no longer valid, we avoid exiting this
* loop and trimming the client buffer later. So we return

View File

@ -3418,7 +3418,9 @@ int processCommand(client *c) {
/* The QUIT command is handled separately. Normal command procs will
* go through checking for replication and QUIT will cause trouble
* when FORCE_REPLICATION is enabled and would be implemented in
* a regular command proc. */
* a regular command proc.
* quit命令
* * */
if (!strcasecmp(c->argv[0]->ptr,"quit")) {
addReply(c,shared.ok);
c->flags |= CLIENT_CLOSE_AFTER_REPLY;

View File

@ -153,7 +153,7 @@ typedef long long ustime_t; /* microsecond time type. */
/* Hash table parameters */
#define HASHTABLE_MIN_FILL 10 /* Minimal hash table fill 10% */
/* Command flags. Please check the command table defined in the redis.c file
/* Command flags. Please check the command table defined in the server.c file
* for more information about the meaning of every flag. */
#define CMD_WRITE (1ULL<<0) /* "write" flag */
#define CMD_READONLY (1ULL<<1) /* "read-only" flag */
@ -721,7 +721,9 @@ typedef struct readyList {
/* This structure represents a Redis user. This is useful for ACLs, the
* user is associated to the connection after the connection is authenticated.
* If there is no associated user, the connection uses the default user. */
* If there is no associated user, the connection uses the default user.
* Redis ACL所有的用户不能超过1024个
* */
#define USER_COMMAND_BITS_COUNT 1024 /* The total number of command bits
in the user structure. The last valid
command ID we can set in the user
@ -736,6 +738,7 @@ typedef struct readyList {
no AUTH is needed, and every
connection is immediately
authenticated. */
/* 用户信息 */
typedef struct {
sds name; /* The username as an SDS string. */
uint64_t flags; /* See USER_FLAG_* */
@ -746,7 +749,9 @@ typedef struct {
*
* If the bit for a given command is NOT set and the command has
* subcommands, Redis will also check allowed_subcommands in order to
* understand if the command can be executed. */
* understand if the command can be executed.
*
* */
uint64_t allowed_commands[USER_COMMAND_BITS_COUNT/64];
/* This array points, for each command ID (corresponding to the command
@ -1428,7 +1433,7 @@ struct redisServer {
long long latency_monitor_threshold;
dict *latency_events;
/* ACLs */
char *acl_filename; /* ACL Users file. NULL if not configured. */
char *acl_filename; /* ACL Users file. NULL if not configured.ACL文件路径需要配置已经存在的文件否则会报错启动失败 */
unsigned long acllog_max_len; /* Maximum length of the ACL LOG list. */
sds requirepass; /* Remember the cleartext password set with the
old "requirepass" directive for backward