Fix permission for newer queries (#156)
This commit is contained in:
parent
8a99670301
commit
13ea35af2d
@ -9,6 +9,8 @@
|
||||
* Fixed memory tracking issues. Some of the allocation and deallocation weren't
|
||||
tracked during the query execution.
|
||||
* Fixed reading CSV files that are using CRLF as the newline symbol.
|
||||
* Fixed permission issues for `LOAD CSV`, `FREE MEMORY`, `LOCK DATA DIRECTORY`,
|
||||
and replication queries.
|
||||
|
||||
## v1.4.0
|
||||
|
||||
|
@ -2232,6 +2232,7 @@ const std::vector<AuthQuery::Privilege> kPrivilegesAll = {
|
||||
AuthQuery::Privilege::AUTH,
|
||||
AuthQuery::Privilege::CONSTRAINT, AuthQuery::Privilege::DUMP,
|
||||
AuthQuery::Privilege::REPLICATION,
|
||||
AuthQuery::Privilege::READ_FILE,
|
||||
AuthQuery::Privilege::LOCK_PATH,
|
||||
AuthQuery::Privilege::FREE_MEMORY};
|
||||
cpp<#
|
||||
|
@ -109,6 +109,6 @@ class ExpressionVisitor
|
||||
template <class TResult>
|
||||
class QueryVisitor
|
||||
: public ::utils::Visitor<TResult, CypherQuery, ExplainQuery, ProfileQuery, IndexQuery, AuthQuery, InfoQuery,
|
||||
ConstraintQuery, DumpQuery, ReplicationQuery, LockPathQuery, LoadCsv, FreeMemoryQuery> {};
|
||||
ConstraintQuery, DumpQuery, ReplicationQuery, LockPathQuery, FreeMemoryQuery> {};
|
||||
|
||||
} // namespace query
|
||||
|
@ -767,6 +767,10 @@ antlrcpp::Any CypherMainVisitor::visitPrivilege(MemgraphCypher::PrivilegeContext
|
||||
if (ctx->AUTH()) return AuthQuery::Privilege::AUTH;
|
||||
if (ctx->CONSTRAINT()) return AuthQuery::Privilege::CONSTRAINT;
|
||||
if (ctx->DUMP()) return AuthQuery::Privilege::DUMP;
|
||||
if (ctx->REPLICATION()) return AuthQuery::Privilege::REPLICATION;
|
||||
if (ctx->LOCK_PATH()) return AuthQuery::Privilege::LOCK_PATH;
|
||||
if (ctx->READ_FILE()) return AuthQuery::Privilege::READ_FILE;
|
||||
if (ctx->FREE_MEMORY()) return AuthQuery::Privilege::FREE_MEMORY;
|
||||
LOG_FATAL("Should not get here - unknown privilege!");
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,7 @@ delimiter : literal ;
|
||||
|
||||
quote : literal ;
|
||||
|
||||
rowVar : variable ;
|
||||
rowVar : variable ;
|
||||
|
||||
userOrRoleName : symbolicName ;
|
||||
|
||||
@ -146,8 +146,22 @@ denyPrivilege : DENY ( ALL PRIVILEGES | privileges=privilegeList ) TO userOrRole
|
||||
|
||||
revokePrivilege : REVOKE ( ALL PRIVILEGES | privileges=privilegeList ) FROM userOrRole=userOrRoleName ;
|
||||
|
||||
privilege : CREATE | DELETE | MATCH | MERGE | SET
|
||||
| REMOVE | INDEX | STATS | AUTH | CONSTRAINT | DUMP ;
|
||||
privilege : CREATE
|
||||
| DELETE
|
||||
| MATCH
|
||||
| MERGE
|
||||
| SET
|
||||
| REMOVE
|
||||
| INDEX
|
||||
| STATS
|
||||
| AUTH
|
||||
| CONSTRAINT
|
||||
| DUMP
|
||||
| REPLICATION
|
||||
| LOCK_PATH
|
||||
| READ_FILE
|
||||
| FREE_MEMORY
|
||||
;
|
||||
|
||||
privilegeList : privilege ( ',' privilege )* ;
|
||||
|
||||
|
@ -10,6 +10,8 @@ lexer grammar MemgraphCypherLexer ;
|
||||
|
||||
import CypherLexer ;
|
||||
|
||||
UNDERSCORE : '_' ;
|
||||
|
||||
ALTER : A L T E R ;
|
||||
ASYNC : A S Y N C ;
|
||||
AUTH : A U T H ;
|
||||
@ -25,6 +27,7 @@ DROP : D R O P ;
|
||||
DUMP : D U M P ;
|
||||
FOR : F O R ;
|
||||
FREE : F R E E ;
|
||||
FREE_MEMORY : F R E E UNDERSCORE M E M O R Y ;
|
||||
FROM : F R O M ;
|
||||
GRANT : G R A N T ;
|
||||
GRANTS : G R A N T S ;
|
||||
@ -33,12 +36,14 @@ IDENTIFIED : I D E N T I F I E D ;
|
||||
IGNORE : I G N O R E ;
|
||||
LOAD : L O A D ;
|
||||
LOCK : L O C K ;
|
||||
LOCK_PATH : L O C K UNDERSCORE P A T H ;
|
||||
MAIN : M A I N ;
|
||||
MODE : M O D E ;
|
||||
NO : N O ;
|
||||
PASSWORD : P A S S W O R D ;
|
||||
PORT : P O R T ;
|
||||
PRIVILEGES : P R I V I L E G E S ;
|
||||
READ_FILE : R E A D UNDERSCORE F I L E ;
|
||||
REGISTER : R E G I S T E R ;
|
||||
REPLICA : R E P L I C A ;
|
||||
REPLICAS : R E P L I C A S ;
|
||||
|
@ -51,74 +51,58 @@ class PrivilegeExtractor : public QueryVisitor<void>, public HierarchicalTreeVis
|
||||
|
||||
void Visit(LockPathQuery &lock_path_query) override { AddPrivilege(AuthQuery::Privilege::LOCK_PATH); }
|
||||
|
||||
void Visit(LoadCsv &load_csv) override { AddPrivilege(AuthQuery::Privilege::READ_FILE); }
|
||||
|
||||
void Visit(FreeMemoryQuery &free_memory_query) override { AddPrivilege(AuthQuery::Privilege::FREE_MEMORY); }
|
||||
|
||||
void Visit(ReplicationQuery &replication_query) override {
|
||||
switch (replication_query.action_) {
|
||||
case ReplicationQuery::Action::SET_REPLICATION_ROLE:
|
||||
AddPrivilege(AuthQuery::Privilege::REPLICATION);
|
||||
break;
|
||||
case ReplicationQuery::Action::SHOW_REPLICATION_ROLE:
|
||||
AddPrivilege(AuthQuery::Privilege::REPLICATION);
|
||||
break;
|
||||
case ReplicationQuery::Action::REGISTER_REPLICA:
|
||||
AddPrivilege(AuthQuery::Privilege::REPLICATION);
|
||||
break;
|
||||
case ReplicationQuery::Action::DROP_REPLICA:
|
||||
AddPrivilege(AuthQuery::Privilege::REPLICATION);
|
||||
break;
|
||||
case ReplicationQuery::Action::SHOW_REPLICAS:
|
||||
AddPrivilege(AuthQuery::Privilege::REPLICATION);
|
||||
break;
|
||||
}
|
||||
}
|
||||
void Visit(ReplicationQuery &replication_query) override { AddPrivilege(AuthQuery::Privilege::REPLICATION); }
|
||||
|
||||
bool PreVisit(Create &) override {
|
||||
bool PreVisit(Create & /*unused*/) override {
|
||||
AddPrivilege(AuthQuery::Privilege::CREATE);
|
||||
return false;
|
||||
}
|
||||
bool PreVisit(CallProcedure &) override {
|
||||
bool PreVisit(CallProcedure & /*unused*/) override {
|
||||
// TODO: Corresponding privilege
|
||||
return false;
|
||||
}
|
||||
bool PreVisit(Delete &) override {
|
||||
bool PreVisit(Delete & /*unused*/) override {
|
||||
AddPrivilege(AuthQuery::Privilege::DELETE);
|
||||
return false;
|
||||
}
|
||||
bool PreVisit(Match &) override {
|
||||
bool PreVisit(Match & /*unused*/) override {
|
||||
AddPrivilege(AuthQuery::Privilege::MATCH);
|
||||
return false;
|
||||
}
|
||||
bool PreVisit(Merge &) override {
|
||||
bool PreVisit(Merge & /*unused*/) override {
|
||||
AddPrivilege(AuthQuery::Privilege::MERGE);
|
||||
return false;
|
||||
}
|
||||
bool PreVisit(SetProperty &) override {
|
||||
bool PreVisit(SetProperty & /*unused*/) override {
|
||||
AddPrivilege(AuthQuery::Privilege::SET);
|
||||
return false;
|
||||
}
|
||||
bool PreVisit(SetProperties &) override {
|
||||
bool PreVisit(SetProperties & /*unused*/) override {
|
||||
AddPrivilege(AuthQuery::Privilege::SET);
|
||||
return false;
|
||||
}
|
||||
bool PreVisit(SetLabels &) override {
|
||||
bool PreVisit(SetLabels & /*unused*/) override {
|
||||
AddPrivilege(AuthQuery::Privilege::SET);
|
||||
return false;
|
||||
}
|
||||
bool PreVisit(RemoveProperty &) override {
|
||||
bool PreVisit(RemoveProperty & /*unused*/) override {
|
||||
AddPrivilege(AuthQuery::Privilege::REMOVE);
|
||||
return false;
|
||||
}
|
||||
bool PreVisit(RemoveLabels &) override {
|
||||
bool PreVisit(RemoveLabels & /*unused*/) override {
|
||||
AddPrivilege(AuthQuery::Privilege::REMOVE);
|
||||
return false;
|
||||
}
|
||||
bool PreVisit(LoadCsv & /*unused*/) override {
|
||||
AddPrivilege(AuthQuery::Privilege::READ_FILE);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Visit(Identifier &) override { return true; }
|
||||
bool Visit(PrimitiveLiteral &) override { return true; }
|
||||
bool Visit(ParameterLookup &) override { return true; }
|
||||
bool Visit(Identifier & /*unused*/) override { return true; }
|
||||
bool Visit(PrimitiveLiteral & /*unused*/) override { return true; }
|
||||
bool Visit(ParameterLookup & /*unused*/) override { return true; }
|
||||
|
||||
private:
|
||||
void AddPrivilege(AuthQuery::Privilege privilege) {
|
||||
|
@ -79,15 +79,15 @@ class Trie {
|
||||
const int kBitsetSize = 65536;
|
||||
|
||||
const trie::Trie kKeywords = {
|
||||
"union", "all", "optional", "match", "unwind", "as", "merge", "on", "create",
|
||||
"set", "detach", "delete", "remove", "with", "distinct", "return", "order", "by",
|
||||
"skip", "limit", "ascending", "asc", "descending", "desc", "where", "or", "xor",
|
||||
"and", "not", "in", "starts", "ends", "contains", "is", "null", "case",
|
||||
"when", "then", "else", "end", "count", "filter", "extract", "any", "none",
|
||||
"single", "true", "false", "reduce", "coalesce", "user", "password", "alter", "drop",
|
||||
"show", "stats", "unique", "explain", "profile", "storage", "index", "info", "exists",
|
||||
"assert", "constraint", "node", "key", "dump", "database", "call", "yield", "memory",
|
||||
"mb", "kb", "unlimited", "free", "procedure", "query"};
|
||||
"union", "all", "optional", "match", "unwind", "as", "merge", "on", "create",
|
||||
"set", "detach", "delete", "remove", "with", "distinct", "return", "order", "by",
|
||||
"skip", "limit", "ascending", "asc", "descending", "desc", "where", "or", "xor",
|
||||
"and", "not", "in", "starts", "ends", "contains", "is", "null", "case",
|
||||
"when", "then", "else", "end", "count", "filter", "extract", "any", "none",
|
||||
"single", "true", "false", "reduce", "coalesce", "user", "password", "alter", "drop",
|
||||
"show", "stats", "unique", "explain", "profile", "storage", "index", "info", "exists",
|
||||
"assert", "constraint", "node", "key", "dump", "database", "call", "yield", "memory",
|
||||
"mb", "kb", "unlimited", "free", "procedure", "query", "free_memory", "read_file", "lock_path"};
|
||||
|
||||
// Unicode codepoints that are allowed at the start of the unescaped name.
|
||||
const std::bitset<kBitsetSize> kUnescapedNameAllowedStarts(
|
||||
|
@ -2053,6 +2053,14 @@ TEST_P(CypherMainVisitorTest, GrantPrivilege) {
|
||||
{AuthQuery::Privilege::CONSTRAINT});
|
||||
check_auth_query(&ast_generator, "GRANT DUMP TO user", AuthQuery::Action::GRANT_PRIVILEGE, "", "", "user", {},
|
||||
{AuthQuery::Privilege::DUMP});
|
||||
check_auth_query(&ast_generator, "GRANT REPLICATION TO user", AuthQuery::Action::GRANT_PRIVILEGE, "", "", "user", {},
|
||||
{AuthQuery::Privilege::REPLICATION});
|
||||
check_auth_query(&ast_generator, "GRANT LOCK_PATH TO user", AuthQuery::Action::GRANT_PRIVILEGE, "", "", "user", {},
|
||||
{AuthQuery::Privilege::LOCK_PATH});
|
||||
check_auth_query(&ast_generator, "GRANT READ_FILE TO user", AuthQuery::Action::GRANT_PRIVILEGE, "", "", "user", {},
|
||||
{AuthQuery::Privilege::READ_FILE});
|
||||
check_auth_query(&ast_generator, "GRANT FREE_MEMORY TO user", AuthQuery::Action::GRANT_PRIVILEGE, "", "", "user", {},
|
||||
{AuthQuery::Privilege::FREE_MEMORY});
|
||||
}
|
||||
|
||||
TEST_P(CypherMainVisitorTest, DenyPrivilege) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "query/frontend/ast/ast_visitor.hpp"
|
||||
#include "query/frontend/semantic/required_privileges.hpp"
|
||||
#include "storage/v2/id_types.hpp"
|
||||
|
||||
@ -131,3 +132,20 @@ TEST_F(TestPrivilegeExtractor, DumpDatabase) {
|
||||
auto *query = storage.Create<DumpQuery>();
|
||||
EXPECT_THAT(GetRequiredPrivileges(query), UnorderedElementsAre(AuthQuery::Privilege::DUMP));
|
||||
}
|
||||
|
||||
TEST_F(TestPrivilegeExtractor, ReadFile) {
|
||||
auto load_csv = storage.Create<LoadCsv>();
|
||||
load_csv->row_var_ = IDENT("row");
|
||||
auto *query = QUERY(SINGLE_QUERY(load_csv));
|
||||
EXPECT_THAT(GetRequiredPrivileges(query), UnorderedElementsAre(AuthQuery::Privilege::READ_FILE));
|
||||
}
|
||||
|
||||
TEST_F(TestPrivilegeExtractor, LockPathQuery) {
|
||||
auto *query = storage.Create<LockPathQuery>();
|
||||
EXPECT_THAT(GetRequiredPrivileges(query), UnorderedElementsAre(AuthQuery::Privilege::LOCK_PATH));
|
||||
}
|
||||
|
||||
TEST_F(TestPrivilegeExtractor, FreeMemoryQuery) {
|
||||
auto *query = storage.Create<FreeMemoryQuery>();
|
||||
EXPECT_THAT(GetRequiredPrivileges(query), UnorderedElementsAre(AuthQuery::Privilege::FREE_MEMORY));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user