ACL: flags refactoring, function to describe user.

This commit is contained in:
antirez 2019-01-31 16:49:22 +01:00
parent 2458e62da4
commit 110c8caf8a
2 changed files with 74 additions and 24 deletions

View File

@ -64,7 +64,19 @@ struct ACLCategoryItem {
{"connection", CMD_CATEGORY_CONNECTION}, {"connection", CMD_CATEGORY_CONNECTION},
{"transaction", CMD_CATEGORY_TRANSACTION}, {"transaction", CMD_CATEGORY_TRANSACTION},
{"scripting", CMD_CATEGORY_SCRIPTING}, {"scripting", CMD_CATEGORY_SCRIPTING},
{"",0} /* Terminator. */ {NULL,0} /* Terminator. */
};
struct ACLUserFlag {
const char *name;
uint64_t flag;
} ACLUserFlags[] = {
{"on", USER_FLAG_ENABLED},
{"off", USER_FLAG_DISABLED},
{"allkeys", USER_FLAG_ALLKEYS},
{"allcommands", USER_FLAG_ALLCOMMANDS},
{"nopass", USER_FLAG_NOPASS},
{NULL,0} /* Terminator. */
}; };
void ACLResetSubcommandsForCommand(user *u, unsigned long id); void ACLResetSubcommandsForCommand(user *u, unsigned long id);
@ -150,7 +162,7 @@ user *ACLCreateUser(const char *name, size_t namelen) {
if (raxFind(Users,(unsigned char*)name,namelen) != raxNotFound) return NULL; if (raxFind(Users,(unsigned char*)name,namelen) != raxNotFound) return NULL;
user *u = zmalloc(sizeof(*u)); user *u = zmalloc(sizeof(*u));
u->name = sdsnewlen(name,namelen); u->name = sdsnewlen(name,namelen);
u->flags = 0; u->flags = USER_FLAG_DISABLED;
u->allowed_subcommands = NULL; u->allowed_subcommands = NULL;
u->passwords = listCreate(); u->passwords = listCreate();
u->patterns = listCreate(); u->patterns = listCreate();
@ -360,6 +372,54 @@ sds ACLDescribeUserCommandRules(user *u) {
return rules; return rules;
} }
/* This is similar to ACLDescribeUserCommandRules(), however instead of
* describing just the user command rules, everything is described: user
* flags, keys, passwords and finally the command rules obtained via
* the ACLDescribeUserCommandRules() function. This is the function we call
* when we want to rewrite the configuration files describing ACLs and
* in order to show users with ACL LIST. */
sds ACLDescribeUser(user *u) {
sds res = sdsempty();
/* Flags. */
for (int j = 0; ACLUserFlags[j].flag; j++) {
if (u->flags & ACLUserFlags[j].flag) {
res = sdscat(res,ACLUserFlags[j].name);
res = sdscatlen(res," ",1);
}
}
/* Passwords. */
listIter li;
listNode *ln;
listRewind(u->passwords,&li);
while((ln = listNext(&li))) {
sds thispass = listNodeValue(ln);
res = sdscatlen(res,">",1);
res = sdscatsds(res,thispass);
res = sdscatlen(res," ",1);
}
/* Key patterns. */
if (u->flags & USER_FLAG_ALLKEYS) {
res = sdscatlen(res,"~* ",3);
} else {
listRewind(u->patterns,&li);
while((ln = listNext(&li))) {
sds thispat = listNodeValue(ln);
res = sdscatlen(res,"~",1);
res = sdscatsds(res,thispat);
res = sdscatlen(res," ",1);
}
}
/* Command rules. */
sds rules = ACLDescribeUserCommandRules(u);
res = sdscatsds(res,rules);
sdsfree(rules);
return res;
}
/* Get a command from the original command table, that is not affected /* Get a command from the original command table, that is not affected
* by the command renaming operations: we base all the ACL work from that * by the command renaming operations: we base all the ACL work from that
* table, so that ACLs are valid regardless of command renaming. */ * table, so that ACLs are valid regardless of command renaming. */
@ -500,7 +560,9 @@ int ACLSetUser(user *u, const char *op, ssize_t oplen) {
if (oplen == -1) oplen = strlen(op); if (oplen == -1) oplen = strlen(op);
if (!strcasecmp(op,"on")) { if (!strcasecmp(op,"on")) {
u->flags |= USER_FLAG_ENABLED; u->flags |= USER_FLAG_ENABLED;
u->flags &= ~USER_FLAG_DISABLED;
} else if (!strcasecmp(op,"off")) { } else if (!strcasecmp(op,"off")) {
u->flags |= USER_FLAG_DISABLED;
u->flags &= ~USER_FLAG_ENABLED; u->flags &= ~USER_FLAG_ENABLED;
} else if (!strcasecmp(op,"allkeys") || } else if (!strcasecmp(op,"allkeys") ||
!strcasecmp(op,"~*")) !strcasecmp(op,"~*"))
@ -679,7 +741,7 @@ int ACLCheckUserCredentials(robj *username, robj *password) {
} }
/* Disabled users can't login. */ /* Disabled users can't login. */
if ((u->flags & USER_FLAG_ENABLED) == 0) { if (u->flags & USER_FLAG_DISABLED) {
errno = EINVAL; errno = EINVAL;
return C_ERR; return C_ERR;
} }
@ -874,24 +936,11 @@ void aclCommand(client *c) {
addReplyBulkCString(c,"flags"); addReplyBulkCString(c,"flags");
void *deflen = addReplyDeferredLen(c); void *deflen = addReplyDeferredLen(c);
int numflags = 0; int numflags = 0;
if (u->flags & USER_FLAG_ENABLED) { for (int j = 0; ACLUserFlags[j].flag; j++) {
addReplyBulkCString(c,"on"); if (u->flags & ACLUserFlags[j].flag) {
numflags++; addReplyBulkCString(c,ACLUserFlags[j].name);
} else { numflags++;
addReplyBulkCString(c,"off"); }
numflags++;
}
if (u->flags & USER_FLAG_ALLKEYS) {
addReplyBulkCString(c,"allkeys");
numflags++;
}
if (u->flags & USER_FLAG_ALLCOMMANDS) {
addReplyBulkCString(c,"allcommands");
numflags++;
}
if (u->flags & USER_FLAG_NOPASS) {
addReplyBulkCString(c,"nopass");
numflags++;
} }
setDeferredSetLen(c,deflen,numflags); setDeferredSetLen(c,deflen,numflags);

View File

@ -740,9 +740,10 @@ typedef struct readyList {
command ID we can set in the user command ID we can set in the user
is USER_COMMAND_BITS_COUNT-1. */ is USER_COMMAND_BITS_COUNT-1. */
#define USER_FLAG_ENABLED (1<<0) /* The user is active. */ #define USER_FLAG_ENABLED (1<<0) /* The user is active. */
#define USER_FLAG_ALLKEYS (1<<1) /* The user can mention any key. */ #define USER_FLAG_DISABLED (1<<1) /* The user is disabled. */
#define USER_FLAG_ALLCOMMANDS (1<<2) /* The user can run all commands. */ #define USER_FLAG_ALLKEYS (1<<2) /* The user can mention any key. */
#define USER_FLAG_NOPASS (1<<3) /* The user requires no password, any #define USER_FLAG_ALLCOMMANDS (1<<3) /* The user can run all commands. */
#define USER_FLAG_NOPASS (1<<4) /* The user requires no password, any
provided password will work. For the provided password will work. For the
default user, this also means that default user, this also means that
no AUTH is needed, and every no AUTH is needed, and every