diff options
author | Madelyn Olson <madelyneolson@gmail.com> | 2020-10-26 21:23:30 -0700 |
---|---|---|
committer | Madelyn Olson <34459052+madolson@users.noreply.github.com> | 2020-10-28 10:01:20 -0700 |
commit | 411bcf1a41d2758823d17e0864ef45e5f3948b7a (patch) | |
tree | 3461741f1ca4694ca3af54d2c0d09bcb01e9249c /src/acl.c | |
parent | efd17316ab122f5ddd9ecd89a98f30759b076a10 (diff) | |
download | redis-411bcf1a41d2758823d17e0864ef45e5f3948b7a.tar.gz |
Further improved ACL algorithm for picking categories
Diffstat (limited to 'src/acl.c')
-rw-r--r-- | src/acl.c | 69 |
1 files changed, 47 insertions, 22 deletions
@@ -479,36 +479,61 @@ sds ACLDescribeUserCommandRules(user *u) { ACLSetUser(fakeuser,"-@all",-1); } - /* Try to add or subtract each category one after the other. Often a - * single category will not perfectly match the set of commands into - * it, so at the end we do a final pass adding/removing the single commands - * needed to make the bitmap exactly match. A temp user is maintained to - * keep track of categories already applied. */ + /* Attempt to find a good approximation for categories and commands + * based on the current bits used, by looping over the category list + * and applying the best fit each time. Often a set of categories will not + * perfectly match the set of commands into it, so at the end we do a + * final pass adding/removing the single commands needed to make the bitmap + * exactly match. A temp user is maintained to keep track of categories + * already applied. */ user tu = {0}; user *tempuser = &tu; memcpy(tempuser->allowed_commands, u->allowed_commands, sizeof(u->allowed_commands)); - - for (int j = 0; ACLCommandCategories[j].flag != 0; j++) { - unsigned long on, off; - ACLCountCategoryBitsForUser(tempuser,&on,&off,ACLCommandCategories[j].name); - if ((additive && on > off) || (!additive && off > on)) { - sds op = sdsnewlen(additive ? "+@" : "-@", 2); - op = sdscat(op,ACLCommandCategories[j].name); - ACLSetUser(fakeuser,op,-1); - - sds invop = sdsnewlen(additive ? "-@" : "+@", 2); - invop = sdscat(invop,ACLCommandCategories[j].name); - ACLSetUser(tempuser,invop,-1); - - rules = sdscatsds(rules,op); - rules = sdscatlen(rules," ",1); - sdsfree(op); - sdsfree(invop); + while (1) { + int best = -1; + unsigned long mindiff = INT_MAX, maxsame = 0; + for (int j = 0; ACLCommandCategories[j].flag != 0; j++) { + unsigned long on, off, diff, same; + ACLCountCategoryBitsForUser(tempuser,&on,&off,ACLCommandCategories[j].name); + + /* Check if the current category is the best this loop: + * * It has more commands in common with the user than commands + * that are different. + * AND EITHER + * * It has the fewest number of differences + * than the best match we have found so far. + * * OR it matches the fewest number of differences + * that we've seen but it has more in common. */ + diff = additive ? off : on; + same = additive ? on : off; + if (same > diff && + ((diff < mindiff) || (diff == mindiff && same > maxsame))) { + best = j; + mindiff = diff; + maxsame = same; + } } + + /* We didn't find a match */ + if (best == -1) break; + + sds op = sdsnewlen(additive ? "+@" : "-@", 2); + op = sdscat(op,ACLCommandCategories[best].name); + ACLSetUser(fakeuser,op,-1); + + sds invop = sdsnewlen(additive ? "-@" : "+@", 2); + invop = sdscat(invop,ACLCommandCategories[best].name); + ACLSetUser(tempuser,invop,-1); + + rules = sdscatsds(rules,op); + rules = sdscatlen(rules," ",1); + sdsfree(op); + sdsfree(invop); } + /* Fix the final ACLs with single commands differences. */ dictIterator *di = dictGetIterator(server.orig_commands); dictEntry *de; |