Add rest of user auth queries
Reviewers: mferencevic, teon.banek Reviewed By: mferencevic, teon.banek Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D1522
This commit is contained in:
parent
ce306a4c21
commit
2a5fce8464
@ -132,14 +132,13 @@ struct Clause {
|
|||||||
merge @10 :Merge;
|
merge @10 :Merge;
|
||||||
unwind @11 :Unwind;
|
unwind @11 :Unwind;
|
||||||
createIndex @12 :CreateIndex;
|
createIndex @12 :CreateIndex;
|
||||||
modifyUser @13 :ModifyUser;
|
authQuery @13 :AuthQuery;
|
||||||
dropUser @14 :DropUser;
|
createStream @14 :CreateStream;
|
||||||
createStream @15 :CreateStream;
|
dropStream @15 :DropStream;
|
||||||
dropStream @16 :DropStream;
|
showStreams @16 :ShowStreams;
|
||||||
showStreams @17 :ShowStreams;
|
startStopStream @17 :StartStopStream;
|
||||||
startStopStream @18 :StartStopStream;
|
startStopAllStreams @18 :StartStopAllStreams;
|
||||||
startStopAllStreams @19 :StartStopAllStreams;
|
testStream @19 :TestStream;
|
||||||
testStream @20 :TestStream;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -398,14 +397,39 @@ struct CreateIndex {
|
|||||||
property @1 :Storage.Common;
|
property @1 :Storage.Common;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ModifyUser {
|
struct AuthQuery {
|
||||||
username @0 :Text;
|
enum Action {
|
||||||
password @1 :Tree;
|
createRole @0;
|
||||||
isCreate @2 :Bool;
|
dropRole @1;
|
||||||
}
|
showRoles @2;
|
||||||
|
createUser @3;
|
||||||
struct DropUser {
|
setPassword @4;
|
||||||
usernames @0 :List(Text);
|
dropUser @5;
|
||||||
|
showUsers @6;
|
||||||
|
grantRole @7;
|
||||||
|
revokeRole @8;
|
||||||
|
grantPrivilege @9;
|
||||||
|
denyPrivilege @10;
|
||||||
|
revokePrivilege @11;
|
||||||
|
showGrants @12;
|
||||||
|
showRoleForUser @13;
|
||||||
|
showUsersForRole @14;
|
||||||
|
}
|
||||||
|
enum Privilege {
|
||||||
|
create @0;
|
||||||
|
delete @1;
|
||||||
|
match @2;
|
||||||
|
merge @3;
|
||||||
|
set @4;
|
||||||
|
auth @5;
|
||||||
|
stream @6;
|
||||||
|
}
|
||||||
|
action @0 :Action;
|
||||||
|
user @1 :Text;
|
||||||
|
role @2 :Text;
|
||||||
|
userOrRole @3 :Text;
|
||||||
|
password @4 :Tree;
|
||||||
|
privileges @5 :List(Privilege);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CreateStream {
|
struct CreateStream {
|
||||||
|
@ -1268,13 +1268,9 @@ Clause *Clause::Construct(const capnp::Clause::Reader &reader,
|
|||||||
auto with_reader = reader.getWith();
|
auto with_reader = reader.getWith();
|
||||||
return With::Construct(with_reader, storage);
|
return With::Construct(with_reader, storage);
|
||||||
}
|
}
|
||||||
case capnp::Clause::MODIFY_USER: {
|
case capnp::Clause::AUTH_QUERY: {
|
||||||
auto mu_reader = reader.getModifyUser();
|
auto aq_reader = reader.getAuthQuery();
|
||||||
return ModifyUser::Construct(mu_reader, storage);
|
return AuthQuery::Construct(aq_reader, storage);
|
||||||
}
|
|
||||||
case capnp::Clause::DROP_USER: {
|
|
||||||
auto du_reader = reader.getDropUser();
|
|
||||||
return DropUser::Construct(du_reader, storage);
|
|
||||||
}
|
}
|
||||||
case capnp::Clause::CREATE_STREAM: {
|
case capnp::Clause::CREATE_STREAM: {
|
||||||
auto cs_reader = reader.getCreateStream();
|
auto cs_reader = reader.getCreateStream();
|
||||||
@ -2067,69 +2063,188 @@ With *With::Construct(const capnp::With::Reader &reader, AstStorage *storage) {
|
|||||||
return storage->Create<With>();
|
return storage->Create<With>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ModifyUser.
|
// AuthQuery.
|
||||||
void ModifyUser::Save(capnp::Clause::Builder *clause_builder,
|
void AuthQuery::Save(capnp::Clause::Builder *clause_builder,
|
||||||
std::vector<int> *saved_uids) {
|
std::vector<int> *saved_uids) {
|
||||||
Clause::Save(clause_builder, saved_uids);
|
Clause::Save(clause_builder, saved_uids);
|
||||||
auto builder = clause_builder->initModifyUser();
|
auto builder = clause_builder->initAuthQuery();
|
||||||
ModifyUser::Save(&builder, saved_uids);
|
AuthQuery::Save(&builder, saved_uids);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModifyUser::Save(capnp::ModifyUser::Builder *builder,
|
void AuthQuery::Save(capnp::AuthQuery::Builder *builder,
|
||||||
std::vector<int> *saved_uids) {
|
std::vector<int> *saved_uids) {
|
||||||
builder->setUsername(username_);
|
switch (action_) {
|
||||||
|
case Action::CREATE_ROLE:
|
||||||
|
builder->setAction(capnp::AuthQuery::Action::CREATE_ROLE);
|
||||||
|
break;
|
||||||
|
case Action::DROP_ROLE:
|
||||||
|
builder->setAction(capnp::AuthQuery::Action::DROP_ROLE);
|
||||||
|
break;
|
||||||
|
case Action::SHOW_ROLES:
|
||||||
|
builder->setAction(capnp::AuthQuery::Action::SHOW_ROLES);
|
||||||
|
break;
|
||||||
|
case Action::CREATE_USER:
|
||||||
|
builder->setAction(capnp::AuthQuery::Action::CREATE_USER);
|
||||||
|
break;
|
||||||
|
case Action::SET_PASSWORD:
|
||||||
|
builder->setAction(capnp::AuthQuery::Action::SET_PASSWORD);
|
||||||
|
break;
|
||||||
|
case Action::DROP_USER:
|
||||||
|
builder->setAction(capnp::AuthQuery::Action::DROP_USER);
|
||||||
|
break;
|
||||||
|
case Action::SHOW_USERS:
|
||||||
|
builder->setAction(capnp::AuthQuery::Action::SHOW_USERS);
|
||||||
|
break;
|
||||||
|
case Action::GRANT_ROLE:
|
||||||
|
builder->setAction(capnp::AuthQuery::Action::GRANT_ROLE);
|
||||||
|
break;
|
||||||
|
case Action::REVOKE_ROLE:
|
||||||
|
builder->setAction(capnp::AuthQuery::Action::REVOKE_ROLE);
|
||||||
|
break;
|
||||||
|
case Action::GRANT_PRIVILEGE:
|
||||||
|
builder->setAction(capnp::AuthQuery::Action::GRANT_PRIVILEGE);
|
||||||
|
break;
|
||||||
|
case Action::DENY_PRIVILEGE:
|
||||||
|
builder->setAction(capnp::AuthQuery::Action::DENY_PRIVILEGE);
|
||||||
|
break;
|
||||||
|
case Action::REVOKE_PRIVILEGE:
|
||||||
|
builder->setAction(capnp::AuthQuery::Action::REVOKE_PRIVILEGE);
|
||||||
|
break;
|
||||||
|
case Action::SHOW_GRANTS:
|
||||||
|
builder->setAction(capnp::AuthQuery::Action::SHOW_GRANTS);
|
||||||
|
break;
|
||||||
|
case Action::SHOW_ROLE_FOR_USER:
|
||||||
|
builder->setAction(capnp::AuthQuery::Action::SHOW_ROLE_FOR_USER);
|
||||||
|
break;
|
||||||
|
case Action::SHOW_USERS_FOR_ROLE:
|
||||||
|
builder->setAction(capnp::AuthQuery::Action::SHOW_USERS_FOR_ROLE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
builder->setUser(user_);
|
||||||
|
builder->setRole(role_);
|
||||||
|
builder->setUserOrRole(user_or_role_);
|
||||||
if (password_) {
|
if (password_) {
|
||||||
auto password_builder = builder->getPassword();
|
auto password_builder = builder->initPassword();
|
||||||
password_->Save(&password_builder, saved_uids);
|
password_->Save(&password_builder, saved_uids);
|
||||||
}
|
}
|
||||||
builder->setIsCreate(is_create_);
|
::capnp::List<capnp::AuthQuery::Privilege>::Builder privileges_builder =
|
||||||
|
builder->initPrivileges(privileges_.size());
|
||||||
|
for (size_t i = 0; i < privileges_.size(); ++i) {
|
||||||
|
switch (privileges_[i]) {
|
||||||
|
case Privilege::CREATE:
|
||||||
|
privileges_builder.set(i, capnp::AuthQuery::Privilege::CREATE);
|
||||||
|
break;
|
||||||
|
case Privilege::DELETE:
|
||||||
|
privileges_builder.set(i, capnp::AuthQuery::Privilege::DELETE);
|
||||||
|
break;
|
||||||
|
case Privilege::MATCH:
|
||||||
|
privileges_builder.set(i, capnp::AuthQuery::Privilege::MATCH);
|
||||||
|
break;
|
||||||
|
case Privilege::MERGE:
|
||||||
|
privileges_builder.set(i, capnp::AuthQuery::Privilege::MERGE);
|
||||||
|
break;
|
||||||
|
case Privilege::SET:
|
||||||
|
privileges_builder.set(i, capnp::AuthQuery::Privilege::SET);
|
||||||
|
break;
|
||||||
|
case Privilege::AUTH:
|
||||||
|
privileges_builder.set(i, capnp::AuthQuery::Privilege::AUTH);
|
||||||
|
break;
|
||||||
|
case Privilege::STREAM:
|
||||||
|
privileges_builder.set(i, capnp::AuthQuery::Privilege::STREAM);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModifyUser::Load(const capnp::Tree::Reader &base_reader,
|
void AuthQuery::Load(const capnp::Tree::Reader &base_reader,
|
||||||
AstStorage *storage, std::vector<int> *loaded_uids) {
|
AstStorage *storage, std::vector<int> *loaded_uids) {
|
||||||
Clause::Load(base_reader, storage, loaded_uids);
|
Clause::Load(base_reader, storage, loaded_uids);
|
||||||
auto reader = base_reader.getClause().getModifyUser();
|
auto auth_reader = base_reader.getClause().getAuthQuery();
|
||||||
username_ = reader.getUsername();
|
switch (auth_reader.getAction()) {
|
||||||
if (reader.hasPassword()) {
|
case capnp::AuthQuery::Action::CREATE_ROLE:
|
||||||
const auto password_reader = reader.getPassword();
|
action_ = Action::CREATE_ROLE;
|
||||||
|
break;
|
||||||
|
case capnp::AuthQuery::Action::DROP_ROLE:
|
||||||
|
action_ = Action::DROP_ROLE;
|
||||||
|
break;
|
||||||
|
case capnp::AuthQuery::Action::SHOW_ROLES:
|
||||||
|
action_ = Action::SHOW_ROLES;
|
||||||
|
break;
|
||||||
|
case capnp::AuthQuery::Action::CREATE_USER:
|
||||||
|
action_ = Action::CREATE_USER;
|
||||||
|
break;
|
||||||
|
case capnp::AuthQuery::Action::SET_PASSWORD:
|
||||||
|
action_ = Action::SET_PASSWORD;
|
||||||
|
break;
|
||||||
|
case capnp::AuthQuery::Action::DROP_USER:
|
||||||
|
action_ = Action::DROP_USER;
|
||||||
|
break;
|
||||||
|
case capnp::AuthQuery::Action::SHOW_USERS:
|
||||||
|
action_ = Action::SHOW_USERS;
|
||||||
|
break;
|
||||||
|
case capnp::AuthQuery::Action::GRANT_ROLE:
|
||||||
|
action_ = Action::GRANT_ROLE;
|
||||||
|
break;
|
||||||
|
case capnp::AuthQuery::Action::REVOKE_ROLE:
|
||||||
|
action_ = Action::REVOKE_ROLE;
|
||||||
|
break;
|
||||||
|
case capnp::AuthQuery::Action::GRANT_PRIVILEGE:
|
||||||
|
action_ = Action::GRANT_PRIVILEGE;
|
||||||
|
break;
|
||||||
|
case capnp::AuthQuery::Action::DENY_PRIVILEGE:
|
||||||
|
action_ = Action::DENY_PRIVILEGE;
|
||||||
|
break;
|
||||||
|
case capnp::AuthQuery::Action::REVOKE_PRIVILEGE:
|
||||||
|
action_ = Action::REVOKE_PRIVILEGE;
|
||||||
|
break;
|
||||||
|
case capnp::AuthQuery::Action::SHOW_GRANTS:
|
||||||
|
action_ = Action::SHOW_GRANTS;
|
||||||
|
break;
|
||||||
|
case capnp::AuthQuery::Action::SHOW_ROLE_FOR_USER:
|
||||||
|
action_ = Action::SHOW_ROLE_FOR_USER;
|
||||||
|
break;
|
||||||
|
case capnp::AuthQuery::Action::SHOW_USERS_FOR_ROLE:
|
||||||
|
action_ = Action::SHOW_USERS_FOR_ROLE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
user_ = auth_reader.getUser();
|
||||||
|
role_ = auth_reader.getRole();
|
||||||
|
user_or_role_ = auth_reader.getUserOrRole();
|
||||||
|
if (auth_reader.hasPassword()) {
|
||||||
|
const auto password_reader = auth_reader.getPassword();
|
||||||
password_ =
|
password_ =
|
||||||
dynamic_cast<Expression *>(storage->Load(password_reader, loaded_uids));
|
dynamic_cast<Expression *>(storage->Load(password_reader, loaded_uids));
|
||||||
} else {
|
|
||||||
password_ = nullptr;
|
|
||||||
}
|
}
|
||||||
is_create_ = reader.getIsCreate();
|
for (const auto &privilege : auth_reader.getPrivileges()) {
|
||||||
|
switch (privilege) {
|
||||||
|
case capnp::AuthQuery::Privilege::CREATE:
|
||||||
|
privileges_.push_back(Privilege::CREATE);
|
||||||
|
break;
|
||||||
|
case capnp::AuthQuery::Privilege::DELETE:
|
||||||
|
privileges_.push_back(Privilege::DELETE);
|
||||||
|
break;
|
||||||
|
case capnp::AuthQuery::Privilege::MATCH:
|
||||||
|
privileges_.push_back(Privilege::MATCH);
|
||||||
|
break;
|
||||||
|
case capnp::AuthQuery::Privilege::MERGE:
|
||||||
|
privileges_.push_back(Privilege::MERGE);
|
||||||
|
break;
|
||||||
|
case capnp::AuthQuery::Privilege::SET:
|
||||||
|
privileges_.push_back(Privilege::SET);
|
||||||
|
break;
|
||||||
|
case capnp::AuthQuery::Privilege::AUTH:
|
||||||
|
privileges_.push_back(Privilege::AUTH);
|
||||||
|
break;
|
||||||
|
case capnp::AuthQuery::Privilege::STREAM:
|
||||||
|
privileges_.push_back(Privilege::STREAM);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ModifyUser *ModifyUser::Construct(const capnp::ModifyUser::Reader &reader,
|
AuthQuery *AuthQuery::Construct(const capnp::AuthQuery::Reader &reader,
|
||||||
AstStorage *storage) {
|
AstStorage *storage) {
|
||||||
return storage->Create<ModifyUser>();
|
return storage->Create<AuthQuery>();
|
||||||
}
|
|
||||||
|
|
||||||
// DropUser.
|
|
||||||
void DropUser::Save(capnp::Clause::Builder *clause_builder,
|
|
||||||
std::vector<int> *saved_uids) {
|
|
||||||
Clause::Save(clause_builder, saved_uids);
|
|
||||||
auto builder = clause_builder->initDropUser();
|
|
||||||
DropUser::Save(&builder, saved_uids);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DropUser::Save(capnp::DropUser::Builder *builder,
|
|
||||||
std::vector<int> *saved_uids) {
|
|
||||||
auto usernames_builder = builder->initUsernames(usernames_.size());
|
|
||||||
utils::SaveVector(usernames_, &usernames_builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DropUser::Load(const capnp::Tree::Reader &base_reader, AstStorage *storage,
|
|
||||||
std::vector<int> *loaded_uids) {
|
|
||||||
Clause::Load(base_reader, storage, loaded_uids);
|
|
||||||
auto reader = base_reader.getClause().getDropUser();
|
|
||||||
usernames_.clear();
|
|
||||||
utils::LoadVector(&usernames_, reader.getUsernames());
|
|
||||||
}
|
|
||||||
|
|
||||||
DropUser *DropUser::Construct(const capnp::DropUser::Reader &reader,
|
|
||||||
AstStorage *storage) {
|
|
||||||
return storage->Create<DropUser>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CypherUnion
|
// CypherUnion
|
||||||
|
@ -2339,68 +2339,67 @@ class CreateIndex : public Clause {
|
|||||||
std::vector<int> *saved_uids);
|
std::vector<int> *saved_uids);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ModifyUser : public Clause {
|
class AuthQuery : public Clause {
|
||||||
friend class AstStorage;
|
friend class AstStorage;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum class Action {
|
||||||
|
CREATE_ROLE,
|
||||||
|
DROP_ROLE,
|
||||||
|
SHOW_ROLES,
|
||||||
|
CREATE_USER,
|
||||||
|
SET_PASSWORD,
|
||||||
|
DROP_USER,
|
||||||
|
SHOW_USERS,
|
||||||
|
GRANT_ROLE,
|
||||||
|
REVOKE_ROLE,
|
||||||
|
GRANT_PRIVILEGE,
|
||||||
|
DENY_PRIVILEGE,
|
||||||
|
REVOKE_PRIVILEGE,
|
||||||
|
SHOW_GRANTS,
|
||||||
|
SHOW_ROLE_FOR_USER,
|
||||||
|
SHOW_USERS_FOR_ROLE
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Privilege { CREATE, DELETE, MATCH, MERGE, SET, AUTH, STREAM };
|
||||||
|
|
||||||
|
Action action_;
|
||||||
|
std::string user_;
|
||||||
|
std::string role_;
|
||||||
|
std::string user_or_role_;
|
||||||
|
Expression *password_{nullptr};
|
||||||
|
std::vector<Privilege> privileges_;
|
||||||
|
|
||||||
DEFVISITABLE(TreeVisitor<TypedValue>);
|
DEFVISITABLE(TreeVisitor<TypedValue>);
|
||||||
DEFVISITABLE(HierarchicalTreeVisitor);
|
DEFVISITABLE(HierarchicalTreeVisitor);
|
||||||
|
|
||||||
ModifyUser *Clone(AstStorage &storage) const override {
|
AuthQuery *Clone(AstStorage &storage) const override {
|
||||||
return storage.Create<ModifyUser>(
|
return storage.Create<AuthQuery>(
|
||||||
username_, password_ ? password_->Clone(storage) : nullptr, is_create_);
|
action_, user_, role_, user_or_role_,
|
||||||
|
password_ ? password_->Clone(storage) : nullptr, privileges_);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ModifyUser *Construct(const capnp::ModifyUser::Reader &reader,
|
static AuthQuery *Construct(const capnp::AuthQuery::Reader &reader,
|
||||||
AstStorage *storage);
|
AstStorage *storage);
|
||||||
using Clause::Save;
|
using Clause::Save;
|
||||||
|
|
||||||
std::string username_;
|
|
||||||
Expression *password_;
|
|
||||||
bool is_create_;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit ModifyUser(int uid) : Clause(uid) {}
|
explicit AuthQuery(int uid) : Clause(uid) {}
|
||||||
ModifyUser(int uid, std::string username, Expression *password,
|
|
||||||
bool is_create)
|
explicit AuthQuery(int uid, Action action, std::string user, std::string role,
|
||||||
|
std::string user_or_role, Expression *password,
|
||||||
|
std::vector<Privilege> privileges)
|
||||||
: Clause(uid),
|
: Clause(uid),
|
||||||
username_(std::move(username)),
|
action_(action),
|
||||||
|
user_(user),
|
||||||
|
role_(role),
|
||||||
|
user_or_role_(user_or_role),
|
||||||
password_(password),
|
password_(password),
|
||||||
is_create_(is_create) {}
|
privileges_(privileges) {}
|
||||||
|
|
||||||
void Save(capnp::Clause::Builder *builder,
|
void Save(capnp::Clause::Builder *builder,
|
||||||
std::vector<int> *saved_uids) override;
|
std::vector<int> *saved_uids) override;
|
||||||
virtual void Save(capnp::ModifyUser::Builder *builder,
|
virtual void Save(capnp::AuthQuery::Builder *builder,
|
||||||
std::vector<int> *saved_uids);
|
|
||||||
void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage,
|
|
||||||
std::vector<int> *loaded_uids) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DropUser : public Clause {
|
|
||||||
friend class AstStorage;
|
|
||||||
|
|
||||||
public:
|
|
||||||
DEFVISITABLE(TreeVisitor<TypedValue>);
|
|
||||||
DEFVISITABLE(HierarchicalTreeVisitor);
|
|
||||||
|
|
||||||
DropUser *Clone(AstStorage &storage) const override {
|
|
||||||
return storage.Create<DropUser>(usernames_);
|
|
||||||
}
|
|
||||||
|
|
||||||
static DropUser *Construct(const capnp::DropUser::Reader &reader,
|
|
||||||
AstStorage *storage);
|
|
||||||
using Clause::Save;
|
|
||||||
|
|
||||||
std::vector<std::string> usernames_;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
explicit DropUser(int uid) : Clause(uid) {}
|
|
||||||
DropUser(int uid, std::vector<std::string> usernames)
|
|
||||||
: Clause(uid), usernames_(usernames) {}
|
|
||||||
|
|
||||||
void Save(capnp::Clause::Builder *builder,
|
|
||||||
std::vector<int> *saved_uids) override;
|
|
||||||
virtual void Save(capnp::DropUser::Builder *builder,
|
|
||||||
std::vector<int> *saved_uids);
|
std::vector<int> *saved_uids);
|
||||||
void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage,
|
void Load(const capnp::Tree::Reader &base_reader, AstStorage *storage,
|
||||||
std::vector<int> *loaded_uids) override;
|
std::vector<int> *loaded_uids) override;
|
||||||
|
@ -61,8 +61,7 @@ class RemoveLabels;
|
|||||||
class Merge;
|
class Merge;
|
||||||
class Unwind;
|
class Unwind;
|
||||||
class CreateIndex;
|
class CreateIndex;
|
||||||
class ModifyUser;
|
class AuthQuery;
|
||||||
class DropUser;
|
|
||||||
class CreateStream;
|
class CreateStream;
|
||||||
class DropStream;
|
class DropStream;
|
||||||
class ShowStreams;
|
class ShowStreams;
|
||||||
@ -84,9 +83,9 @@ using TreeCompositeVisitor = ::utils::CompositeVisitor<
|
|||||||
|
|
||||||
using TreeLeafVisitor =
|
using TreeLeafVisitor =
|
||||||
::utils::LeafVisitor<Identifier, PrimitiveLiteral, ParameterLookup,
|
::utils::LeafVisitor<Identifier, PrimitiveLiteral, ParameterLookup,
|
||||||
CreateIndex, ModifyUser, DropUser, CreateStream,
|
CreateIndex, AuthQuery, CreateStream, DropStream,
|
||||||
DropStream, ShowStreams, StartStopStream,
|
ShowStreams, StartStopStream, StartStopAllStreams,
|
||||||
StartStopAllStreams, TestStream>;
|
TestStream>;
|
||||||
|
|
||||||
class HierarchicalTreeVisitor : public TreeCompositeVisitor,
|
class HierarchicalTreeVisitor : public TreeCompositeVisitor,
|
||||||
public TreeLeafVisitor {
|
public TreeLeafVisitor {
|
||||||
@ -109,8 +108,7 @@ using TreeVisitor = ::utils::Visitor<
|
|||||||
Aggregation, Function, Reduce, Extract, All, Single, ParameterLookup,
|
Aggregation, Function, Reduce, Extract, All, Single, ParameterLookup,
|
||||||
Create, Match, Return, With, Pattern, NodeAtom, EdgeAtom, Delete, Where,
|
Create, Match, Return, With, Pattern, NodeAtom, EdgeAtom, Delete, Where,
|
||||||
SetProperty, SetProperties, SetLabels, RemoveProperty, RemoveLabels, Merge,
|
SetProperty, SetProperties, SetLabels, RemoveProperty, RemoveLabels, Merge,
|
||||||
Unwind, Identifier, PrimitiveLiteral, CreateIndex, ModifyUser, DropUser,
|
Unwind, Identifier, PrimitiveLiteral, CreateIndex, AuthQuery, CreateStream,
|
||||||
CreateStream, DropStream, ShowStreams, StartStopStream, StartStopAllStreams,
|
DropStream, ShowStreams, StartStopStream, StartStopAllStreams, TestStream>;
|
||||||
TestStream>;
|
|
||||||
|
|
||||||
} // namespace query
|
} // namespace query
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <regex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@ -28,13 +29,10 @@ antlrcpp::Any CypherMainVisitor::visitAuthQuery(
|
|||||||
MemgraphCypher::AuthQueryContext *ctx) {
|
MemgraphCypher::AuthQueryContext *ctx) {
|
||||||
query_ = storage_.query();
|
query_ = storage_.query();
|
||||||
query_->single_query_ = storage_.Create<SingleQuery>();
|
query_->single_query_ = storage_.Create<SingleQuery>();
|
||||||
Clause *clause = nullptr;
|
CHECK(ctx->children.size() == 1)
|
||||||
if (ctx->modifyUser()) {
|
<< "AuthQuery should have exactly one child!";
|
||||||
clause = ctx->modifyUser()->accept(this).as<ModifyUser *>();
|
query_->single_query_->clauses_.push_back(
|
||||||
} else if (ctx->dropUser()) {
|
ctx->children[0]->accept(this).as<AuthQuery *>());
|
||||||
clause = ctx->dropUser()->accept(this).as<DropUser *>();
|
|
||||||
}
|
|
||||||
query_->single_query_->clauses_ = {clause};
|
|
||||||
return query_;
|
return query_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -259,46 +257,224 @@ antlrcpp::Any CypherMainVisitor::visitCreateIndex(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return ModifyUser*
|
* @return std::string
|
||||||
*/
|
*/
|
||||||
antlrcpp::Any CypherMainVisitor::visitModifyUser(
|
antlrcpp::Any CypherMainVisitor::visitUserOrRoleName(
|
||||||
MemgraphCypher::ModifyUserContext *ctx) {
|
MemgraphCypher::UserOrRoleNameContext *ctx) {
|
||||||
std::string username(ctx->userName->getText());
|
std::string value = ctx->symbolicName()->accept(this).as<std::string>();
|
||||||
Expression *password = nullptr;
|
const std::regex NAME_REGEX("[a-zA-Z0-9_.+-]+");
|
||||||
bool is_create = static_cast<bool>(ctx->CREATE());
|
if (!std::regex_match(value, NAME_REGEX)) {
|
||||||
for (auto option : ctx->modifyUserOption()) {
|
throw SyntaxException("invalid user or role name");
|
||||||
if (option->passwordOption()) {
|
|
||||||
if (password) {
|
|
||||||
throw QueryException("password should be set at most once");
|
|
||||||
}
|
|
||||||
password = option->passwordOption()->accept(this);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
LOG(FATAL) << "Expected to handle all cases above.";
|
|
||||||
}
|
}
|
||||||
return storage_.Create<ModifyUser>(username, password, is_create);
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Expression*
|
* @return AuthQuery*
|
||||||
*/
|
*/
|
||||||
antlrcpp::Any CypherMainVisitor::visitPasswordOption(
|
antlrcpp::Any CypherMainVisitor::visitCreateRole(
|
||||||
MemgraphCypher::PasswordOptionContext *ctx) {
|
MemgraphCypher::CreateRoleContext *ctx) {
|
||||||
if (!ctx->literal()->StringLiteral() && !ctx->literal()->CYPHERNULL()) {
|
AuthQuery *auth = storage_.Create<AuthQuery>();
|
||||||
|
auth->action_ = AuthQuery::Action::CREATE_ROLE;
|
||||||
|
auth->role_ = ctx->role->accept(this).as<std::string>();
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any CypherMainVisitor::visitDropRole(
|
||||||
|
MemgraphCypher::DropRoleContext *ctx) {
|
||||||
|
AuthQuery *auth = storage_.Create<AuthQuery>();
|
||||||
|
auth->action_ = AuthQuery::Action::DROP_ROLE;
|
||||||
|
auth->role_ = ctx->role->accept(this).as<std::string>();
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any CypherMainVisitor::visitShowRoles(
|
||||||
|
MemgraphCypher::ShowRolesContext *ctx) {
|
||||||
|
AuthQuery *auth = storage_.Create<AuthQuery>();
|
||||||
|
auth->action_ = AuthQuery::Action::SHOW_ROLES;
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any CypherMainVisitor::visitCreateUser(
|
||||||
|
MemgraphCypher::CreateUserContext *ctx) {
|
||||||
|
AuthQuery *auth = storage_.Create<AuthQuery>();
|
||||||
|
auth->action_ = AuthQuery::Action::CREATE_USER;
|
||||||
|
auth->user_ = ctx->user->accept(this).as<std::string>();
|
||||||
|
if (ctx->password) {
|
||||||
|
if (!ctx->password->StringLiteral() && !ctx->literal()->CYPHERNULL()) {
|
||||||
|
throw SyntaxException("password should be a string literal or NULL");
|
||||||
|
}
|
||||||
|
auth->password_ = ctx->password->accept(this);
|
||||||
|
}
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any CypherMainVisitor::visitSetPassword(
|
||||||
|
MemgraphCypher::SetPasswordContext *ctx) {
|
||||||
|
AuthQuery *auth = storage_.Create<AuthQuery>();
|
||||||
|
auth->action_ = AuthQuery::Action::SET_PASSWORD;
|
||||||
|
auth->user_ = ctx->user->accept(this).as<std::string>();
|
||||||
|
if (!ctx->password->StringLiteral() && !ctx->literal()->CYPHERNULL()) {
|
||||||
throw SyntaxException("password should be a string literal or NULL");
|
throw SyntaxException("password should be a string literal or NULL");
|
||||||
}
|
}
|
||||||
return ctx->literal()->accept(this);
|
auth->password_ = ctx->password->accept(this);
|
||||||
|
return auth;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return DropUser*
|
* @return AuthQuery*
|
||||||
*/
|
*/
|
||||||
antlrcpp::Any CypherMainVisitor::visitDropUser(
|
antlrcpp::Any CypherMainVisitor::visitDropUser(
|
||||||
MemgraphCypher::DropUserContext *ctx) {
|
MemgraphCypher::DropUserContext *ctx) {
|
||||||
std::vector<std::string> usernames;
|
AuthQuery *auth = storage_.Create<AuthQuery>();
|
||||||
for (auto username_ptr : ctx->userName)
|
auth->action_ = AuthQuery::Action::DROP_USER;
|
||||||
usernames.emplace_back(username_ptr->getText());
|
auth->user_ = ctx->user->accept(this).as<std::string>();
|
||||||
return storage_.Create<DropUser>(usernames);
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any CypherMainVisitor::visitShowUsers(
|
||||||
|
MemgraphCypher::ShowUsersContext *ctx) {
|
||||||
|
AuthQuery *auth = storage_.Create<AuthQuery>();
|
||||||
|
auth->action_ = AuthQuery::Action::SHOW_USERS;
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any CypherMainVisitor::visitGrantRole(
|
||||||
|
MemgraphCypher::GrantRoleContext *ctx) {
|
||||||
|
AuthQuery *auth = storage_.Create<AuthQuery>();
|
||||||
|
auth->action_ = AuthQuery::Action::GRANT_ROLE;
|
||||||
|
auth->role_ = ctx->role->accept(this).as<std::string>();
|
||||||
|
auth->user_ = ctx->user->accept(this).as<std::string>();
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any CypherMainVisitor::visitRevokeRole(
|
||||||
|
MemgraphCypher::RevokeRoleContext *ctx) {
|
||||||
|
AuthQuery *auth = storage_.Create<AuthQuery>();
|
||||||
|
auth->action_ = AuthQuery::Action::REVOKE_ROLE;
|
||||||
|
auth->role_ = ctx->role->accept(this).as<std::string>();
|
||||||
|
auth->user_ = ctx->user->accept(this).as<std::string>();
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any CypherMainVisitor::visitGrantPrivilege(
|
||||||
|
MemgraphCypher::GrantPrivilegeContext *ctx) {
|
||||||
|
AuthQuery *auth = storage_.Create<AuthQuery>();
|
||||||
|
auth->action_ = AuthQuery::Action::GRANT_PRIVILEGE;
|
||||||
|
auth->user_or_role_ = ctx->userOrRole->accept(this).as<std::string>();
|
||||||
|
for (auto *privilege : ctx->privilegeList()->privilege()) {
|
||||||
|
auth->privileges_.push_back(privilege->accept(this));
|
||||||
|
}
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any CypherMainVisitor::visitDenyPrivilege(
|
||||||
|
MemgraphCypher::DenyPrivilegeContext *ctx) {
|
||||||
|
AuthQuery *auth = storage_.Create<AuthQuery>();
|
||||||
|
auth->action_ = AuthQuery::Action::DENY_PRIVILEGE;
|
||||||
|
auth->user_or_role_ = ctx->userOrRole->accept(this).as<std::string>();
|
||||||
|
for (auto *privilege : ctx->privilegeList()->privilege()) {
|
||||||
|
auth->privileges_.push_back(privilege->accept(this));
|
||||||
|
}
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any CypherMainVisitor::visitRevokePrivilege(
|
||||||
|
MemgraphCypher::RevokePrivilegeContext *ctx) {
|
||||||
|
AuthQuery *auth = storage_.Create<AuthQuery>();
|
||||||
|
auth->action_ = AuthQuery::Action::REVOKE_PRIVILEGE;
|
||||||
|
auth->user_or_role_ = ctx->userOrRole->accept(this).as<std::string>();
|
||||||
|
if (ctx->privilegeList()) {
|
||||||
|
for (auto *privilege : ctx->privilegeList()->privilege()) {
|
||||||
|
auth->privileges_.push_back(privilege->accept(this));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* revoke all privileges */
|
||||||
|
auth->privileges_ = {
|
||||||
|
AuthQuery::Privilege::CREATE, AuthQuery::Privilege::DELETE,
|
||||||
|
AuthQuery::Privilege::MATCH, AuthQuery::Privilege::MERGE,
|
||||||
|
AuthQuery::Privilege::SET, AuthQuery::Privilege::AUTH,
|
||||||
|
AuthQuery::Privilege::STREAM};
|
||||||
|
}
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery::Privilege
|
||||||
|
*/
|
||||||
|
antlrcpp::Any CypherMainVisitor::visitPrivilege(
|
||||||
|
MemgraphCypher::PrivilegeContext *ctx) {
|
||||||
|
if (ctx->CREATE()) return AuthQuery::Privilege::CREATE;
|
||||||
|
if (ctx->DELETE()) return AuthQuery::Privilege::DELETE;
|
||||||
|
if (ctx->MATCH()) return AuthQuery::Privilege::MATCH;
|
||||||
|
if (ctx->MERGE()) return AuthQuery::Privilege::MERGE;
|
||||||
|
if (ctx->SET()) return AuthQuery::Privilege::SET;
|
||||||
|
if (ctx->AUTH()) return AuthQuery::Privilege::AUTH;
|
||||||
|
if (ctx->STREAM()) return AuthQuery::Privilege::STREAM;
|
||||||
|
LOG(FATAL) << "Should not get here - unknown privilege!";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any CypherMainVisitor::visitShowGrants(
|
||||||
|
MemgraphCypher::ShowGrantsContext *ctx) {
|
||||||
|
AuthQuery *auth = storage_.Create<AuthQuery>();
|
||||||
|
auth->action_ = AuthQuery::Action::SHOW_GRANTS;
|
||||||
|
auth->user_or_role_ = ctx->userOrRole->accept(this).as<std::string>();
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any CypherMainVisitor::visitShowRoleForUser(
|
||||||
|
MemgraphCypher::ShowRoleForUserContext *ctx) {
|
||||||
|
AuthQuery *auth = storage_.Create<AuthQuery>();
|
||||||
|
auth->action_ = AuthQuery::Action::SHOW_ROLE_FOR_USER;
|
||||||
|
auth->user_ = ctx->user->accept(this).as<std::string>();
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any CypherMainVisitor::visitShowUsersForRole(
|
||||||
|
MemgraphCypher::ShowUsersForRoleContext *ctx) {
|
||||||
|
AuthQuery *auth = storage_.Create<AuthQuery>();
|
||||||
|
auth->action_ = AuthQuery::Action::SHOW_USERS_FOR_ROLE;
|
||||||
|
auth->role_ = ctx->role->accept(this).as<std::string>();
|
||||||
|
return auth;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -177,6 +177,28 @@ class CypherMainVisitor : public antlropencypher::MemgraphCypherBaseVisitor {
|
|||||||
*/
|
*/
|
||||||
antlrcpp::Any visitCreate(MemgraphCypher::CreateContext *ctx) override;
|
antlrcpp::Any visitCreate(MemgraphCypher::CreateContext *ctx) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return std::string
|
||||||
|
*/
|
||||||
|
antlrcpp::Any visitUserOrRoleName(
|
||||||
|
MemgraphCypher::UserOrRoleNameContext *ctx) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any visitCreateRole(
|
||||||
|
MemgraphCypher::CreateRoleContext *ctx) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any visitDropRole(MemgraphCypher::DropRoleContext *ctx) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any visitShowRoles(MemgraphCypher::ShowRolesContext *ctx) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return CreateIndex*
|
* @return CreateIndex*
|
||||||
*/
|
*/
|
||||||
@ -184,19 +206,79 @@ class CypherMainVisitor : public antlropencypher::MemgraphCypherBaseVisitor {
|
|||||||
MemgraphCypher::CreateIndexContext *ctx) override;
|
MemgraphCypher::CreateIndexContext *ctx) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return ModifyUser*
|
* @return AuthQuery*
|
||||||
*/
|
*/
|
||||||
antlrcpp::Any visitModifyUser(
|
antlrcpp::Any visitCreateUser(
|
||||||
MemgraphCypher::ModifyUserContext *ctx) override;
|
MemgraphCypher::CreateUserContext *ctx) override;
|
||||||
|
|
||||||
antlrcpp::Any visitPasswordOption(
|
|
||||||
MemgraphCypher::PasswordOptionContext *ctx) override;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return DropUser*
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any visitSetPassword(
|
||||||
|
MemgraphCypher::SetPasswordContext *ctx) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
*/
|
*/
|
||||||
antlrcpp::Any visitDropUser(MemgraphCypher::DropUserContext *ctx) override;
|
antlrcpp::Any visitDropUser(MemgraphCypher::DropUserContext *ctx) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any visitShowUsers(MemgraphCypher::ShowUsersContext *ctx) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any visitGrantRole(MemgraphCypher::GrantRoleContext *ctx) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any visitRevokeRole(
|
||||||
|
MemgraphCypher::RevokeRoleContext *ctx) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any visitGrantPrivilege(
|
||||||
|
MemgraphCypher::GrantPrivilegeContext *ctx) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any visitDenyPrivilege(
|
||||||
|
MemgraphCypher::DenyPrivilegeContext *ctx) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any visitRevokePrivilege(
|
||||||
|
MemgraphCypher::RevokePrivilegeContext *ctx) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery::Privilege
|
||||||
|
*/
|
||||||
|
antlrcpp::Any visitPrivilege(MemgraphCypher::PrivilegeContext *ctx) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any visitShowGrants(
|
||||||
|
MemgraphCypher::ShowGrantsContext *ctx) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any visitShowRoleForUser(
|
||||||
|
MemgraphCypher::ShowRoleForUserContext *ctx) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return AuthQuery*
|
||||||
|
*/
|
||||||
|
antlrcpp::Any visitShowUsersForRole(
|
||||||
|
MemgraphCypher::ShowUsersForRoleContext *ctx) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return CreateStream*
|
* @return CreateStream*
|
||||||
*/
|
*/
|
||||||
|
@ -8,23 +8,36 @@ import Cypher ;
|
|||||||
|
|
||||||
memgraphCypherKeyword : cypherKeyword
|
memgraphCypherKeyword : cypherKeyword
|
||||||
| ALTER
|
| ALTER
|
||||||
|
| AUTH
|
||||||
| BATCH
|
| BATCH
|
||||||
| BATCHES
|
| BATCHES
|
||||||
| DATA
|
| DATA
|
||||||
|
| DENY
|
||||||
| DROP
|
| DROP
|
||||||
|
| FOR
|
||||||
|
| FROM
|
||||||
|
| GRANT
|
||||||
|
| GRANTS
|
||||||
|
| IDENTIFIED
|
||||||
| INTERVAL
|
| INTERVAL
|
||||||
| K_TEST
|
| K_TEST
|
||||||
| KAFKA
|
| KAFKA
|
||||||
| LOAD
|
| LOAD
|
||||||
| PASSWORD
|
| PASSWORD
|
||||||
|
| PRIVILEGES
|
||||||
|
| REVOKE
|
||||||
|
| ROLE
|
||||||
|
| ROLES
|
||||||
| SIZE
|
| SIZE
|
||||||
| START
|
| START
|
||||||
| STOP
|
| STOP
|
||||||
| STREAM
|
| STREAM
|
||||||
| STREAMS
|
| STREAMS
|
||||||
|
| TO
|
||||||
| TOPIC
|
| TOPIC
|
||||||
| TRANSFORM
|
| TRANSFORM
|
||||||
| USER
|
| USER
|
||||||
|
| USERS
|
||||||
;
|
;
|
||||||
|
|
||||||
symbolicName : UnescapedSymbolicName
|
symbolicName : UnescapedSymbolicName
|
||||||
@ -37,19 +50,60 @@ query : regularQuery
|
|||||||
| streamQuery
|
| streamQuery
|
||||||
;
|
;
|
||||||
|
|
||||||
authQuery : modifyUser
|
authQuery : createRole
|
||||||
|
| dropRole
|
||||||
|
| showRoles
|
||||||
|
| createUser
|
||||||
|
| setPassword
|
||||||
| dropUser
|
| dropUser
|
||||||
|
| showUsers
|
||||||
|
| grantRole
|
||||||
|
| revokeRole
|
||||||
|
| grantPrivilege
|
||||||
|
| denyPrivilege
|
||||||
|
| revokePrivilege
|
||||||
|
| showGrants
|
||||||
|
| showRoleForUser
|
||||||
|
| showUsersForRole
|
||||||
;
|
;
|
||||||
|
|
||||||
modifyUser : ( CREATE | ALTER ) USER userName=UnescapedSymbolicName
|
userOrRoleName : symbolicName ;
|
||||||
( WITH ( modifyUserOption )+ )? ;
|
|
||||||
|
|
||||||
modifyUserOption : passwordOption ;
|
createRole : CREATE ROLE role=userOrRoleName ;
|
||||||
|
|
||||||
passwordOption : PASSWORD literal;
|
dropRole : DROP ROLE role=userOrRoleName ;
|
||||||
|
|
||||||
dropUser : DROP USER userName+=UnescapedSymbolicName
|
showRoles : SHOW ROLES ;
|
||||||
( ',' userName+=UnescapedSymbolicName )* ;
|
|
||||||
|
createUser : CREATE USER user=userOrRoleName
|
||||||
|
( IDENTIFIED BY password=literal )? ;
|
||||||
|
|
||||||
|
setPassword : SET PASSWORD FOR user=userOrRoleName TO password=literal;
|
||||||
|
|
||||||
|
dropUser : DROP USER user=userOrRoleName ;
|
||||||
|
|
||||||
|
showUsers : SHOW USERS ;
|
||||||
|
|
||||||
|
grantRole : GRANT ROLE role=userOrRoleName TO user=userOrRoleName ;
|
||||||
|
|
||||||
|
revokeRole : REVOKE ROLE role=userOrRoleName FROM user=userOrRoleName ;
|
||||||
|
|
||||||
|
grantPrivilege : GRANT privilegeList TO userOrRole=userOrRoleName ;
|
||||||
|
|
||||||
|
denyPrivilege : DENY privilegeList TO userOrRole=userOrRoleName ;
|
||||||
|
|
||||||
|
revokePrivilege : REVOKE ( ALL PRIVILEGES | privileges=privilegeList ) FROM userOrRole=userOrRoleName ;
|
||||||
|
|
||||||
|
privilege : CREATE | DELETE | MATCH | MERGE | SET
|
||||||
|
| AUTH | STREAM ;
|
||||||
|
|
||||||
|
privilegeList : privilege ( ',' privilege )* ;
|
||||||
|
|
||||||
|
showGrants : SHOW GRANTS FOR userOrRole=userOrRoleName ;
|
||||||
|
|
||||||
|
showRoleForUser : SHOW ROLE FOR USER user=userOrRoleName ;
|
||||||
|
|
||||||
|
showUsersForRole : SHOW USERS FOR ROLE role=userOrRoleName ;
|
||||||
|
|
||||||
streamQuery : createStream
|
streamQuery : createStream
|
||||||
| dropStream
|
| dropStream
|
||||||
|
@ -11,20 +11,33 @@ lexer grammar MemgraphCypherLexer ;
|
|||||||
import CypherLexer ;
|
import CypherLexer ;
|
||||||
|
|
||||||
ALTER : A L T E R ;
|
ALTER : A L T E R ;
|
||||||
|
AUTH : A U T H ;
|
||||||
BATCH : B A T C H ;
|
BATCH : B A T C H ;
|
||||||
BATCHES : B A T C H E S ;
|
BATCHES : B A T C H E S ;
|
||||||
DATA : D A T A ;
|
DATA : D A T A ;
|
||||||
|
DENY : D E N Y ;
|
||||||
DROP : D R O P ;
|
DROP : D R O P ;
|
||||||
|
FOR : F O R ;
|
||||||
|
FROM : F R O M ;
|
||||||
|
GRANT : G R A N T ;
|
||||||
|
GRANTS : G R A N T S ;
|
||||||
|
IDENTIFIED : I D E N T I F I E D ;
|
||||||
INTERVAL : I N T E R V A L ;
|
INTERVAL : I N T E R V A L ;
|
||||||
K_TEST : T E S T ;
|
K_TEST : T E S T ;
|
||||||
KAFKA : K A F K A ;
|
KAFKA : K A F K A ;
|
||||||
LOAD : L O A D ;
|
LOAD : L O A D ;
|
||||||
PASSWORD : P A S S W O R D ;
|
PASSWORD : P A S S W O R D ;
|
||||||
|
PRIVILEGES : P R I V I L E G E S ;
|
||||||
|
REVOKE : R E V O K E ;
|
||||||
|
ROLE : R O L E ;
|
||||||
|
ROLES : R O L E S ;
|
||||||
SIZE : S I Z E ;
|
SIZE : S I Z E ;
|
||||||
START : S T A R T ;
|
START : S T A R T ;
|
||||||
STOP : S T O P ;
|
STOP : S T O P ;
|
||||||
STREAM : S T R E A M ;
|
STREAM : S T R E A M ;
|
||||||
STREAMS : S T R E A M S ;
|
STREAMS : S T R E A M S ;
|
||||||
|
TO : T O ;
|
||||||
TOPIC : T O P I C ;
|
TOPIC : T O P I C ;
|
||||||
TRANSFORM : T R A N S F O R M ;
|
TRANSFORM : T R A N S F O R M ;
|
||||||
USER : U S E R ;
|
USER : U S E R ;
|
||||||
|
USERS : U S E R S ;
|
||||||
|
@ -220,9 +220,7 @@ bool SymbolGenerator::PostVisit(Match &) {
|
|||||||
|
|
||||||
bool SymbolGenerator::Visit(CreateIndex &) { return true; }
|
bool SymbolGenerator::Visit(CreateIndex &) { return true; }
|
||||||
|
|
||||||
bool SymbolGenerator::Visit(ModifyUser &) { return true; }
|
bool SymbolGenerator::Visit(AuthQuery &) { return true; }
|
||||||
|
|
||||||
bool SymbolGenerator::Visit(DropUser &) { return true; }
|
|
||||||
|
|
||||||
bool SymbolGenerator::Visit(CreateStream &) { return true; }
|
bool SymbolGenerator::Visit(CreateStream &) { return true; }
|
||||||
|
|
||||||
|
@ -47,8 +47,7 @@ class SymbolGenerator : public HierarchicalTreeVisitor {
|
|||||||
bool PreVisit(Match &) override;
|
bool PreVisit(Match &) override;
|
||||||
bool PostVisit(Match &) override;
|
bool PostVisit(Match &) override;
|
||||||
bool Visit(CreateIndex &) override;
|
bool Visit(CreateIndex &) override;
|
||||||
bool Visit(ModifyUser &) override;
|
bool Visit(AuthQuery &) override;
|
||||||
bool Visit(DropUser &) override;
|
|
||||||
bool Visit(CreateStream &) override;
|
bool Visit(CreateStream &) override;
|
||||||
bool Visit(DropStream &) override;
|
bool Visit(DropStream &) override;
|
||||||
bool Visit(ShowStreams &) override;
|
bool Visit(ShowStreams &) override;
|
||||||
|
@ -49,8 +49,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
|
|||||||
BLOCK_VISIT(Merge);
|
BLOCK_VISIT(Merge);
|
||||||
BLOCK_VISIT(Unwind);
|
BLOCK_VISIT(Unwind);
|
||||||
BLOCK_VISIT(CreateIndex);
|
BLOCK_VISIT(CreateIndex);
|
||||||
BLOCK_VISIT(ModifyUser);
|
BLOCK_VISIT(AuthQuery);
|
||||||
BLOCK_VISIT(DropUser);
|
|
||||||
BLOCK_VISIT(CreateStream);
|
BLOCK_VISIT(CreateStream);
|
||||||
BLOCK_VISIT(DropStream);
|
BLOCK_VISIT(DropStream);
|
||||||
BLOCK_VISIT(ShowStreams);
|
BLOCK_VISIT(ShowStreams);
|
||||||
|
@ -185,8 +185,7 @@ class CostEstimator : public HierarchicalLogicalOperatorVisitor {
|
|||||||
|
|
||||||
bool Visit(Once &) override { return true; }
|
bool Visit(Once &) override { return true; }
|
||||||
bool Visit(CreateIndex &) override { return true; }
|
bool Visit(CreateIndex &) override { return true; }
|
||||||
bool Visit(ModifyUser &) override { return true; }
|
bool Visit(AuthHandler &) override { return true; }
|
||||||
bool Visit(DropUser &) override { return true; }
|
|
||||||
bool Visit(CreateStream &) override { return true; }
|
bool Visit(CreateStream &) override { return true; }
|
||||||
bool Visit(DropStream &) override { return true; }
|
bool Visit(DropStream &) override { return true; }
|
||||||
bool Visit(ShowStreams &) override { return true; }
|
bool Visit(ShowStreams &) override { return true; }
|
||||||
|
@ -87,8 +87,7 @@ class IndependentSubtreeFinder : public HierarchicalLogicalOperatorVisitor {
|
|||||||
// These don't use any symbols
|
// These don't use any symbols
|
||||||
bool Visit(Once &) override { return true; }
|
bool Visit(Once &) override { return true; }
|
||||||
bool Visit(CreateIndex &) override { return true; }
|
bool Visit(CreateIndex &) override { return true; }
|
||||||
bool Visit(ModifyUser &) override { return true; }
|
bool Visit(AuthHandler &) override { return true; }
|
||||||
bool Visit(DropUser &) override { return true; }
|
|
||||||
bool Visit(CreateStream &) override { return true; }
|
bool Visit(CreateStream &) override { return true; }
|
||||||
bool Visit(DropStream &) override { return true; }
|
bool Visit(DropStream &) override { return true; }
|
||||||
bool Visit(ShowStreams &) override { return true; }
|
bool Visit(ShowStreams &) override { return true; }
|
||||||
@ -1344,9 +1343,7 @@ class DistributedPlanner : public HierarchicalLogicalOperatorVisitor {
|
|||||||
|
|
||||||
bool Visit(CreateIndex &) override { return true; }
|
bool Visit(CreateIndex &) override { return true; }
|
||||||
|
|
||||||
bool Visit(ModifyUser &) override { return true; }
|
bool Visit(AuthHandler &) override { return true; }
|
||||||
|
|
||||||
bool Visit(DropUser &) override { return true; }
|
|
||||||
|
|
||||||
bool Visit(CreateStream &) override { return true; }
|
bool Visit(CreateStream &) override { return true; }
|
||||||
|
|
||||||
|
@ -159,7 +159,7 @@ VertexAccessor &CreateVertexOnWorker(int worker_id, NodeAtom *node_atom,
|
|||||||
int current_worker_id = 0;
|
int current_worker_id = 0;
|
||||||
// TODO: Figure out a better solution.
|
// TODO: Figure out a better solution.
|
||||||
if (auto *distributed_db =
|
if (auto *distributed_db =
|
||||||
dynamic_cast<database::DistributedGraphDb *>(&dba.db())) {
|
dynamic_cast<database::DistributedGraphDb *>(&dba.db())) {
|
||||||
current_worker_id = distributed_db->WorkerId();
|
current_worker_id = distributed_db->WorkerId();
|
||||||
} else {
|
} else {
|
||||||
CHECK(dynamic_cast<database::SingleNode *>(&dba.db()));
|
CHECK(dynamic_cast<database::SingleNode *>(&dba.db()));
|
||||||
@ -1392,7 +1392,8 @@ class ExpandWeightedShortestPathCursor : public query::plan::Cursor {
|
|||||||
// For the given (edge, vertex, weight, depth) tuple checks if they
|
// For the given (edge, vertex, weight, depth) tuple checks if they
|
||||||
// satisfy the "where" condition. if so, places them in the priority queue.
|
// satisfy the "where" condition. if so, places them in the priority queue.
|
||||||
auto expand_pair = [this, &evaluator, &frame, &create_state](
|
auto expand_pair = [this, &evaluator, &frame, &create_state](
|
||||||
EdgeAccessor edge, VertexAccessor vertex, double weight, int depth) {
|
EdgeAccessor edge, VertexAccessor vertex,
|
||||||
|
double weight, int depth) {
|
||||||
SwitchAccessor(edge, self_.graph_view_);
|
SwitchAccessor(edge, self_.graph_view_);
|
||||||
SwitchAccessor(vertex, self_.graph_view_);
|
SwitchAccessor(vertex, self_.graph_view_);
|
||||||
|
|
||||||
@ -3889,130 +3890,120 @@ std::unique_ptr<Cursor> PullRemoteOrderBy::MakeCursor(
|
|||||||
return std::make_unique<PullRemoteOrderByCursor>(*this, db);
|
return std::make_unique<PullRemoteOrderByCursor>(*this, db);
|
||||||
}
|
}
|
||||||
|
|
||||||
ModifyUser::ModifyUser(std::string username, Expression *password,
|
AuthHandler::AuthHandler(AuthQuery::Action action, std::string user,
|
||||||
bool is_create)
|
std::string role, std::string user_or_role,
|
||||||
: username_(std::move(username)),
|
Expression *password,
|
||||||
|
std::vector<AuthQuery::Privilege> privileges)
|
||||||
|
: action_(action),
|
||||||
|
user_(user),
|
||||||
|
role_(role),
|
||||||
|
user_or_role_(user_or_role),
|
||||||
password_(password),
|
password_(password),
|
||||||
is_create_(is_create) {}
|
privileges_(privileges) {}
|
||||||
|
|
||||||
bool ModifyUser::Accept(HierarchicalLogicalOperatorVisitor &visitor) {
|
bool AuthHandler::Accept(HierarchicalLogicalOperatorVisitor &visitor) {
|
||||||
return visitor.Visit(*this);
|
return visitor.Visit(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
WITHOUT_SINGLE_INPUT(ModifyUser)
|
class AuthHandlerCursor : public Cursor {
|
||||||
|
|
||||||
class ModifyUserCursor : public Cursor {
|
|
||||||
public:
|
public:
|
||||||
ModifyUserCursor(const ModifyUser &self) : self_(self) {}
|
AuthHandlerCursor(const AuthHandler &self) : self_(self) {}
|
||||||
|
|
||||||
bool Pull(Frame &frame, Context &ctx) override {
|
bool Pull(Frame &frame, Context &ctx) override {
|
||||||
if (ctx.in_explicit_transaction_) {
|
if (ctx.in_explicit_transaction_) {
|
||||||
throw UserModificationInMulticommandTxException();
|
throw UserModificationInMulticommandTxException();
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpressionEvaluator evaluator(frame, &ctx, GraphView::OLD);
|
ExpressionEvaluator evaluator(frame, &ctx, GraphView::OLD);
|
||||||
|
std::experimental::optional<std::string> password;
|
||||||
TypedValue password_tv = self_.password()->Accept(evaluator);
|
/* TODO(mferencevic): handle null passwords properly */
|
||||||
if (password_tv.type() != TypedValue::Type::String) {
|
if (self_.password()) {
|
||||||
throw QueryRuntimeException(fmt::format(
|
auto password_tv = self_.password()->Accept(evaluator);
|
||||||
"Password must be a string, not '{}'", password_tv.type()));
|
if (!password_tv.IsString()) {
|
||||||
}
|
throw QueryRuntimeException("Password must be a string, not '{}'!",
|
||||||
|
password_tv.type());
|
||||||
// All of the following operations are done with a lock.
|
|
||||||
std::lock_guard<std::mutex> guard(ctx.auth_->WithLock());
|
|
||||||
|
|
||||||
std::experimental::optional<auth::User> user;
|
|
||||||
if (self_.is_create()) {
|
|
||||||
// Create a new user.
|
|
||||||
user = ctx.auth_->AddUser(self_.username());
|
|
||||||
if (!user) {
|
|
||||||
throw QueryRuntimeException(
|
|
||||||
fmt::format("User '{}' already exists!", self_.username()));
|
|
||||||
}
|
}
|
||||||
} else {
|
password = password_tv.ValueString();
|
||||||
// Update an existing user.
|
}
|
||||||
user = ctx.auth_->GetUser(self_.username());
|
|
||||||
if (!user) {
|
auto &auth = *ctx.auth_;
|
||||||
throw QueryRuntimeException(
|
std::lock_guard<std::mutex> lock(auth.WithLock());
|
||||||
fmt::format("User '{}' doesn't exist!", self_.username()));
|
|
||||||
|
switch (self_.action()) {
|
||||||
|
case AuthQuery::Action::CREATE_USER: {
|
||||||
|
if (!password) {
|
||||||
|
throw QueryRuntimeException(
|
||||||
|
"Password must be provided when creating a user!");
|
||||||
|
}
|
||||||
|
auto user = auth.AddUser(self_.user());
|
||||||
|
if (!user) {
|
||||||
|
throw QueryRuntimeException("User '{}' already exists!",
|
||||||
|
self_.user());
|
||||||
|
}
|
||||||
|
user->UpdatePassword(*password);
|
||||||
|
if (!auth.SaveUser(*user)) {
|
||||||
|
throw QueryRuntimeException("Couldn't save user '{}'!", self_.user());
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
case AuthQuery::Action::DROP_USER: {
|
||||||
|
auto user = auth.GetUser(self_.user());
|
||||||
|
if (!user) {
|
||||||
|
throw QueryRuntimeException("User '{}' doesn't exist!", self_.user());
|
||||||
|
}
|
||||||
|
if (!auth.RemoveUser(self_.user())) {
|
||||||
|
throw QueryRuntimeException("Couldn't remove user '{}'!",
|
||||||
|
self_.user());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AuthQuery::Action::SET_PASSWORD: {
|
||||||
|
if (!password) {
|
||||||
|
throw QueryRuntimeException("Password must be provided!");
|
||||||
|
}
|
||||||
|
auto user = auth.GetUser(self_.user());
|
||||||
|
if (!user) {
|
||||||
|
throw QueryRuntimeException("User '{}' doesn't exist!", self_.user());
|
||||||
|
}
|
||||||
|
user->UpdatePassword(*password);
|
||||||
|
if (!auth.SaveUser(*user)) {
|
||||||
|
throw QueryRuntimeException("Couldn't set password for user '{}'!",
|
||||||
|
self_.user());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AuthQuery::Action::CREATE_ROLE:
|
||||||
|
case AuthQuery::Action::DROP_ROLE:
|
||||||
|
case AuthQuery::Action::SHOW_ROLES:
|
||||||
|
case AuthQuery::Action::SHOW_USERS:
|
||||||
|
case AuthQuery::Action::GRANT_ROLE:
|
||||||
|
case AuthQuery::Action::REVOKE_ROLE:
|
||||||
|
case AuthQuery::Action::GRANT_PRIVILEGE:
|
||||||
|
case AuthQuery::Action::DENY_PRIVILEGE:
|
||||||
|
case AuthQuery::Action::REVOKE_PRIVILEGE:
|
||||||
|
case AuthQuery::Action::SHOW_GRANTS:
|
||||||
|
case AuthQuery::Action::SHOW_ROLE_FOR_USER:
|
||||||
|
case AuthQuery::Action::SHOW_USERS_FOR_ROLE:
|
||||||
|
throw utils::NotYetImplemented("user auth");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the password and save the user.
|
|
||||||
user->UpdatePassword(password_tv.Value<std::string>());
|
|
||||||
if (!ctx.auth_->SaveUser(*user)) {
|
|
||||||
throw QueryRuntimeException(
|
|
||||||
fmt::format("Couldn't save user '{}'!", self_.username()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reset() override {}
|
void Reset() override {
|
||||||
|
LOG(FATAL) << "AuthHandler cursor should never be reset";
|
||||||
private:
|
|
||||||
const ModifyUser &self_;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unique_ptr<Cursor> ModifyUser::MakeCursor(
|
|
||||||
database::GraphDbAccessor &) const {
|
|
||||||
return std::make_unique<ModifyUserCursor>(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DropUser::Accept(HierarchicalLogicalOperatorVisitor &visitor) {
|
|
||||||
return visitor.Visit(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
WITHOUT_SINGLE_INPUT(DropUser)
|
|
||||||
|
|
||||||
class DropUserCursor : public Cursor {
|
|
||||||
public:
|
|
||||||
DropUserCursor(const DropUser &self) : self_(self) {}
|
|
||||||
|
|
||||||
bool Pull(Frame &, Context &ctx) override {
|
|
||||||
if (ctx.in_explicit_transaction_) {
|
|
||||||
throw UserModificationInMulticommandTxException();
|
|
||||||
}
|
|
||||||
|
|
||||||
// All of the following operations are done with a lock.
|
|
||||||
std::lock_guard<std::mutex> guard(ctx.auth_->WithLock());
|
|
||||||
|
|
||||||
// Check if all users exist.
|
|
||||||
for (const auto &username : self_.usernames()) {
|
|
||||||
auto user = ctx.auth_->GetUser(username);
|
|
||||||
if (!user) {
|
|
||||||
throw QueryRuntimeException(
|
|
||||||
fmt::format("User '{}' doesn't exist!", username));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete all users.
|
|
||||||
std::vector<std::string> failed;
|
|
||||||
for (const auto &username : self_.usernames()) {
|
|
||||||
if (!ctx.auth_->RemoveUser(username)) {
|
|
||||||
failed.push_back(username);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for failures.
|
|
||||||
if (failed.size() > 0) {
|
|
||||||
throw QueryRuntimeException(fmt::format("Couldn't remove users: '{}'!",
|
|
||||||
utils::Join(failed, "', '")));
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Reset() override {}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const DropUser &self_;
|
const AuthHandler &self_;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<Cursor> DropUser::MakeCursor(
|
std::unique_ptr<Cursor> AuthHandler::MakeCursor(
|
||||||
database::GraphDbAccessor &) const {
|
database::GraphDbAccessor &db) const {
|
||||||
return std::make_unique<DropUserCursor>(*this);
|
return std::make_unique<AuthHandlerCursor>(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WITHOUT_SINGLE_INPUT(AuthHandler)
|
||||||
|
|
||||||
CreateStream::CreateStream(std::string stream_name, Expression *stream_uri,
|
CreateStream::CreateStream(std::string stream_name, Expression *stream_uri,
|
||||||
Expression *stream_topic, Expression *transform_uri,
|
Expression *stream_topic, Expression *transform_uri,
|
||||||
Expression *batch_interval_in_ms,
|
Expression *batch_interval_in_ms,
|
||||||
|
@ -102,8 +102,7 @@ class PullRemote;
|
|||||||
class Synchronize;
|
class Synchronize;
|
||||||
class Cartesian;
|
class Cartesian;
|
||||||
class PullRemoteOrderBy;
|
class PullRemoteOrderBy;
|
||||||
class ModifyUser;
|
class AuthHandler;
|
||||||
class DropUser;
|
|
||||||
class CreateStream;
|
class CreateStream;
|
||||||
class DropStream;
|
class DropStream;
|
||||||
class ShowStreams;
|
class ShowStreams;
|
||||||
@ -122,9 +121,9 @@ using LogicalOperatorCompositeVisitor = ::utils::CompositeVisitor<
|
|||||||
Cartesian, PullRemoteOrderBy>;
|
Cartesian, PullRemoteOrderBy>;
|
||||||
|
|
||||||
using LogicalOperatorLeafVisitor =
|
using LogicalOperatorLeafVisitor =
|
||||||
::utils::LeafVisitor<Once, CreateIndex, ModifyUser, DropUser,
|
::utils::LeafVisitor<Once, CreateIndex, AuthHandler, CreateStream,
|
||||||
CreateStream, DropStream, ShowStreams,
|
DropStream, ShowStreams, StartStopStream,
|
||||||
StartStopStream, StartStopAllStreams, TestStream>;
|
StartStopAllStreams, TestStream>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Base class for hierarhical visitors of @c LogicalOperator class
|
* @brief Base class for hierarhical visitors of @c LogicalOperator class
|
||||||
@ -1969,6 +1968,114 @@ and returns true, once.")
|
|||||||
cpp<#)
|
cpp<#)
|
||||||
(:serialize :capnp))
|
(:serialize :capnp))
|
||||||
|
|
||||||
|
(lcp:define-class auth-handler (logical-operator)
|
||||||
|
((action "AuthQuery::Action" :reader t
|
||||||
|
:capnp-init nil
|
||||||
|
:capnp-type "Ast.AuthQuery.Action"
|
||||||
|
:capnp-save (lcp:capnp-save-enum "::query::capnp::AuthQuery::Action"
|
||||||
|
"AuthQuery::Action"
|
||||||
|
'(create-role drop-role show-roles
|
||||||
|
create-user set-password
|
||||||
|
drop-user show-users grant-role
|
||||||
|
revoke-role grant-privilege
|
||||||
|
deny-privilege revoke-privilege
|
||||||
|
show-grants show-role-for-user
|
||||||
|
show-users-for-role))
|
||||||
|
:capnp-load (lcp:capnp-load-enum "::query::capnp::AuthQuery::Action"
|
||||||
|
"AuthQuery::Action"
|
||||||
|
'(create-role drop-role show-roles
|
||||||
|
create-user set-password
|
||||||
|
drop-user show-users grant-role
|
||||||
|
revoke-role grant-privilege
|
||||||
|
deny-privilege revoke-privilege
|
||||||
|
show-grants show-role-for-user
|
||||||
|
show-users-for-role)))
|
||||||
|
(user "std::string" :reader t)
|
||||||
|
(role "std::string" :reader t)
|
||||||
|
(user-or-role "std::string" :reader t)
|
||||||
|
(password "Expression *" :reader t
|
||||||
|
:capnp-type "Ast.Tree" :capnp-init nil
|
||||||
|
:capnp-save #'save-ast-pointer
|
||||||
|
:capnp-load (load-ast-pointer "Expression *"))
|
||||||
|
(privileges "std::vector<AuthQuery::Privilege>" :reader t
|
||||||
|
:capnp-type "List(Ast.AuthQuery.Privilege)"
|
||||||
|
:capnp-save
|
||||||
|
(lambda (builder member-name)
|
||||||
|
#>cpp
|
||||||
|
for (size_t i = 0; i < ${member-name}.size(); ++i) {
|
||||||
|
switch (privileges_[i]) {
|
||||||
|
case AuthQuery::Privilege::CREATE:
|
||||||
|
${builder}.set(i, query::capnp::AuthQuery::Privilege::CREATE);
|
||||||
|
break;
|
||||||
|
case AuthQuery::Privilege::DELETE:
|
||||||
|
${builder}.set(i, query::capnp::AuthQuery::Privilege::DELETE);
|
||||||
|
break;
|
||||||
|
case AuthQuery::Privilege::MATCH:
|
||||||
|
${builder}.set(i, query::capnp::AuthQuery::Privilege::MATCH);
|
||||||
|
break;
|
||||||
|
case AuthQuery::Privilege::MERGE:
|
||||||
|
${builder}.set(i, query::capnp::AuthQuery::Privilege::MERGE);
|
||||||
|
break;
|
||||||
|
case AuthQuery::Privilege::SET:
|
||||||
|
${builder}.set(i, query::capnp::AuthQuery::Privilege::SET);
|
||||||
|
break;
|
||||||
|
case AuthQuery::Privilege::AUTH:
|
||||||
|
${builder}.set(i, query::capnp::AuthQuery::Privilege::AUTH);
|
||||||
|
break;
|
||||||
|
case AuthQuery::Privilege::STREAM:
|
||||||
|
${builder}.set(i, query::capnp::AuthQuery::Privilege::STREAM);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cpp<#)
|
||||||
|
:capnp-load
|
||||||
|
(lambda (reader member-name)
|
||||||
|
#>cpp
|
||||||
|
for (auto privilege : ${reader}) {
|
||||||
|
switch (privilege) {
|
||||||
|
case query::capnp::AuthQuery::Privilege::CREATE:
|
||||||
|
${member-name}.push_back(AuthQuery::Privilege::CREATE);
|
||||||
|
break;
|
||||||
|
case query::capnp::AuthQuery::Privilege::DELETE:
|
||||||
|
${member-name}.push_back(AuthQuery::Privilege::DELETE);
|
||||||
|
break;
|
||||||
|
case query::capnp::AuthQuery::Privilege::MATCH:
|
||||||
|
${member-name}.push_back(AuthQuery::Privilege::MATCH);
|
||||||
|
break;
|
||||||
|
case query::capnp::AuthQuery::Privilege::MERGE:
|
||||||
|
${member-name}.push_back(AuthQuery::Privilege::MERGE);
|
||||||
|
break;
|
||||||
|
case query::capnp::AuthQuery::Privilege::SET:
|
||||||
|
${member-name}.push_back(AuthQuery::Privilege::SET);
|
||||||
|
break;
|
||||||
|
case query::capnp::AuthQuery::Privilege::AUTH:
|
||||||
|
${member-name}.push_back(AuthQuery::Privilege::AUTH);
|
||||||
|
break;
|
||||||
|
case query::capnp::AuthQuery::Privilege::STREAM:
|
||||||
|
${member-name}.push_back(AuthQuery::Privilege::STREAM);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cpp<#)))
|
||||||
|
(:public
|
||||||
|
#>cpp
|
||||||
|
AuthHandler(AuthQuery::Action action, std::string user, std::string role,
|
||||||
|
std::string user_or_role, Expression * password,
|
||||||
|
std::vector<AuthQuery::Privilege> privileges);
|
||||||
|
|
||||||
|
bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override;
|
||||||
|
std::unique_ptr<Cursor> MakeCursor(database::GraphDbAccessor & db)
|
||||||
|
const override;
|
||||||
|
virtual std::vector<Symbol> ModifiedSymbols(const SymbolTable &)
|
||||||
|
const override { return {}; }
|
||||||
|
|
||||||
|
bool HasSingleInput() const override;
|
||||||
|
std::shared_ptr<LogicalOperator> input() const override;
|
||||||
|
void set_input(std::shared_ptr<LogicalOperator>) override;
|
||||||
|
cpp<#)
|
||||||
|
(:protected #>cpp AuthHandler() {} cpp<#)
|
||||||
|
(:serialize :capnp))
|
||||||
|
|
||||||
(lcp:define-class unwind (logical-operator)
|
(lcp:define-class unwind (logical-operator)
|
||||||
((input "std::shared_ptr<LogicalOperator>"
|
((input "std::shared_ptr<LogicalOperator>"
|
||||||
:capnp-save #'save-operator-pointer
|
:capnp-save #'save-operator-pointer
|
||||||
@ -1991,8 +2098,10 @@ Input is optional (unwind can be the first clause in a query).")
|
|||||||
database::GraphDbAccessor &db) const override;
|
database::GraphDbAccessor &db) const override;
|
||||||
std::vector<Symbol> ModifiedSymbols(const SymbolTable &) const override;
|
std::vector<Symbol> ModifiedSymbols(const SymbolTable &) const override;
|
||||||
|
|
||||||
bool HasSingleInput() const override { return true; }
|
bool HasSingleInput() const override {
|
||||||
std::shared_ptr<LogicalOperator> input() const override { return input_; }
|
return true; }
|
||||||
|
std::shared_ptr<LogicalOperator> input() const override {
|
||||||
|
return input_; }
|
||||||
void set_input(std::shared_ptr<LogicalOperator> input) override {
|
void set_input(std::shared_ptr<LogicalOperator> input) override {
|
||||||
input_ = input;
|
input_ = input;
|
||||||
}
|
}
|
||||||
@ -2338,70 +2447,6 @@ by having only one result from each worker.")
|
|||||||
(:private #>cpp PullRemoteOrderBy() {} cpp<#)
|
(:private #>cpp PullRemoteOrderBy() {} cpp<#)
|
||||||
(:serialize :capnp))
|
(:serialize :capnp))
|
||||||
|
|
||||||
(lcp:define-class modify-user (logical-operator)
|
|
||||||
((input "std::shared_ptr<LogicalOperator>"
|
|
||||||
:capnp-save #'save-operator-pointer
|
|
||||||
:capnp-load #'load-operator-pointer)
|
|
||||||
(username "std::string" :reader t)
|
|
||||||
(password "Expression *" :reader t
|
|
||||||
:capnp-type "Ast.Tree"
|
|
||||||
:capnp-init nil
|
|
||||||
:capnp-save #'save-ast-pointer
|
|
||||||
:capnp-load (load-ast-pointer "Expression *"))
|
|
||||||
(is-create :bool :reader t))
|
|
||||||
(:documentation
|
|
||||||
"Operator that creates a new database user or modifies an existing one.")
|
|
||||||
(:public
|
|
||||||
#>cpp
|
|
||||||
ModifyUser(std::string username, Expression *password, bool is_create);
|
|
||||||
|
|
||||||
bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override;
|
|
||||||
std::unique_ptr<Cursor> MakeCursor(
|
|
||||||
database::GraphDbAccessor &db) const override;
|
|
||||||
|
|
||||||
std::vector<Symbol> ModifiedSymbols(const SymbolTable &) const override {
|
|
||||||
return std::vector<Symbol>();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HasSingleInput() const override;
|
|
||||||
std::shared_ptr<LogicalOperator> input() const override;
|
|
||||||
void set_input(std::shared_ptr<LogicalOperator> input) override;
|
|
||||||
cpp<#)
|
|
||||||
(:private
|
|
||||||
#>cpp
|
|
||||||
ModifyUser() {}
|
|
||||||
cpp<#)
|
|
||||||
(:serialize :capnp))
|
|
||||||
|
|
||||||
(lcp:define-class drop-user (logical-operator)
|
|
||||||
((input "std::shared_ptr<LogicalOperator>"
|
|
||||||
:capnp-save #'save-operator-pointer
|
|
||||||
:capnp-load #'load-operator-pointer)
|
|
||||||
(usernames "std::vector<std::string>" :reader t))
|
|
||||||
(:documentation
|
|
||||||
"Operator that deletes one or more existing database users.")
|
|
||||||
(:public
|
|
||||||
#>cpp
|
|
||||||
DropUser(std::vector<std::string> usernames): usernames_(usernames) {}
|
|
||||||
|
|
||||||
bool Accept(HierarchicalLogicalOperatorVisitor &visitor) override;
|
|
||||||
std::unique_ptr<Cursor> MakeCursor(
|
|
||||||
database::GraphDbAccessor &db) const override;
|
|
||||||
|
|
||||||
std::vector<Symbol> ModifiedSymbols(const SymbolTable &) const override {
|
|
||||||
return std::vector<Symbol>();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HasSingleInput() const override;
|
|
||||||
std::shared_ptr<LogicalOperator> input() const override;
|
|
||||||
void set_input(std::shared_ptr<LogicalOperator> input) override;
|
|
||||||
cpp<#)
|
|
||||||
(:private
|
|
||||||
#>cpp
|
|
||||||
DropUser() {}
|
|
||||||
cpp<#)
|
|
||||||
(:serialize :capnp))
|
|
||||||
|
|
||||||
(lcp:define-class create-stream (logical-operator)
|
(lcp:define-class create-stream (logical-operator)
|
||||||
((stream-name "std::string" :reader t)
|
((stream-name "std::string" :reader t)
|
||||||
(stream-uri "Expression *"
|
(stream-uri "Expression *"
|
||||||
|
@ -53,8 +53,7 @@ class UsedSymbolsCollector : public HierarchicalTreeVisitor {
|
|||||||
bool Visit(PrimitiveLiteral &) override { return true; }
|
bool Visit(PrimitiveLiteral &) override { return true; }
|
||||||
bool Visit(ParameterLookup &) override { return true; }
|
bool Visit(ParameterLookup &) override { return true; }
|
||||||
bool Visit(query::CreateIndex &) override { return true; }
|
bool Visit(query::CreateIndex &) override { return true; }
|
||||||
bool Visit(query::ModifyUser &) override { return true; }
|
bool Visit(query::AuthQuery &) override { return true; }
|
||||||
bool Visit(query::DropUser &) override { return true; }
|
|
||||||
bool Visit(query::CreateStream &) override { return true; }
|
bool Visit(query::CreateStream &) override { return true; }
|
||||||
bool Visit(query::DropStream &) override { return true; }
|
bool Visit(query::DropStream &) override { return true; }
|
||||||
bool Visit(query::ShowStreams &) override { return true; }
|
bool Visit(query::ShowStreams &) override { return true; }
|
||||||
|
@ -402,12 +402,7 @@ class ReturnBodyContext : public HierarchicalTreeVisitor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Visit(query::ModifyUser &) override {
|
bool Visit(query::AuthQuery &) override {
|
||||||
has_aggregation_.emplace_back(false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Visit(query::DropUser &) override {
|
|
||||||
has_aggregation_.emplace_back(false);
|
has_aggregation_.emplace_back(false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -182,15 +182,13 @@ class RuleBasedPlanner {
|
|||||||
DCHECK(!input_op) << "Unexpected operator before CreateIndex";
|
DCHECK(!input_op) << "Unexpected operator before CreateIndex";
|
||||||
input_op = std::make_unique<plan::CreateIndex>(
|
input_op = std::make_unique<plan::CreateIndex>(
|
||||||
create_index->label_, create_index->property_);
|
create_index->label_, create_index->property_);
|
||||||
} else if (auto *modify_user =
|
} else if (auto *auth_query =
|
||||||
dynamic_cast<query::ModifyUser *>(clause)) {
|
dynamic_cast<query::AuthQuery *>(clause)) {
|
||||||
DCHECK(!input_op) << "Unexpected operator before ModifyUser";
|
DCHECK(!input_op) << "Unexpected operator before AuthQuery";
|
||||||
input_op = std::make_unique<plan::ModifyUser>(
|
input_op = std::make_unique<plan::AuthHandler>(
|
||||||
modify_user->username_, modify_user->password_,
|
auth_query->action_, auth_query->user_, auth_query->role_,
|
||||||
modify_user->is_create_);
|
auth_query->user_or_role_, auth_query->password_,
|
||||||
} else if (auto *drop_user = dynamic_cast<query::DropUser *>(clause)) {
|
auth_query->privileges_);
|
||||||
DCHECK(!input_op) << "Unexpected operator before DropUser";
|
|
||||||
input_op = std::make_unique<plan::DropUser>(drop_user->usernames_);
|
|
||||||
} else if (auto *create_stream =
|
} else if (auto *create_stream =
|
||||||
dynamic_cast<query::CreateStream *>(clause)) {
|
dynamic_cast<query::CreateStream *>(clause)) {
|
||||||
DCHECK(!input_op) << "Unexpected operator before CreateStream";
|
DCHECK(!input_op) << "Unexpected operator before CreateStream";
|
||||||
|
@ -514,13 +514,8 @@ class PlanPrinter : public query::plan::HierarchicalLogicalOperatorVisitor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Visit(query::plan::ModifyUser &op) override {
|
bool Visit(query::plan::AuthHandler &op) override {
|
||||||
WithPrintLn([](auto &out) { out << "* ModifyUser "; });
|
WithPrintLn([](auto &out) { out << "* AuthHandler"; });
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Visit(query::plan::DropUser &op) override {
|
|
||||||
WithPrintLn([](auto &out) { out << "* DropUser"; });
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1866,72 +1866,203 @@ TYPED_TEST(CypherMainVisitorTest, UnionAll) {
|
|||||||
ASSERT_FALSE(return_clause->body_.distinct);
|
ASSERT_FALSE(return_clause->body_.distinct);
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST(CypherMainVisitorTest, ModifyUser) {
|
template <typename AstGeneratorT>
|
||||||
auto check_modify_user = [](std::string input, std::string username,
|
void check_auth_query(std::string input, AuthQuery::Action action,
|
||||||
std::experimental::optional<TypedValue> password,
|
std::string user, std::string role,
|
||||||
bool is_create) {
|
std::string user_or_role,
|
||||||
TypeParam ast_generator(input);
|
std::experimental::optional<TypedValue> password,
|
||||||
auto *query = ast_generator.query_;
|
std::vector<AuthQuery::Privilege> privileges) {
|
||||||
ASSERT_TRUE(query->single_query_);
|
AstGeneratorT ast_generator(input);
|
||||||
auto *single_query = query->single_query_;
|
auto *query = ast_generator.query_;
|
||||||
ASSERT_EQ(single_query->clauses_.size(), 1U);
|
ASSERT_TRUE(query->single_query_ &&
|
||||||
auto *create_user = dynamic_cast<ModifyUser *>(single_query->clauses_[0]);
|
query->single_query_->clauses_.size() == 1U);
|
||||||
ASSERT_TRUE(create_user);
|
auto auth_query =
|
||||||
EXPECT_EQ(create_user->username_, username);
|
dynamic_cast<AuthQuery *>(query->single_query_->clauses_[0]);
|
||||||
if (password) {
|
EXPECT_EQ(auth_query->action_, action);
|
||||||
ASSERT_NE(create_user->password_, nullptr);
|
EXPECT_EQ(auth_query->user_, user);
|
||||||
CheckLiteral(ast_generator.context_, create_user->password_, *password);
|
EXPECT_EQ(auth_query->role_, role);
|
||||||
} else {
|
EXPECT_EQ(auth_query->user_or_role_, user_or_role);
|
||||||
EXPECT_EQ(create_user->password_, nullptr);
|
ASSERT_EQ(static_cast<bool>(auth_query->password_),
|
||||||
}
|
static_cast<bool>(password));
|
||||||
EXPECT_EQ(create_user->is_create_, is_create);
|
if (password) {
|
||||||
};
|
CheckLiteral(ast_generator.context_, auth_query->password_, *password);
|
||||||
|
}
|
||||||
|
EXPECT_EQ(auth_query->privileges_, privileges);
|
||||||
|
}
|
||||||
|
|
||||||
check_modify_user("CreaTE UsEr dominik", "dominik",
|
TYPED_TEST(CypherMainVisitorTest, UserOrRoleName) {
|
||||||
std::experimental::nullopt, true);
|
ASSERT_THROW(TypeParam("CREATE ROLE `us|er`"), SyntaxException);
|
||||||
check_modify_user("CreaTE UsEr dominik WIth PaSSWORD 'spomenik'", "dominik",
|
ASSERT_THROW(TypeParam("CREATE ROLE `us er`"), SyntaxException);
|
||||||
"spomenik", true);
|
check_auth_query<TypeParam>("CREATE ROLE `user`",
|
||||||
check_modify_user("CreaTE UsEr dominik WIth PaSSWORD NULL", "dominik",
|
AuthQuery::Action::CREATE_ROLE, "", "user", "",
|
||||||
TypedValue::Null, true);
|
{}, {});
|
||||||
check_modify_user("AlTeR UsEr dominik", "dominik", std::experimental::nullopt,
|
check_auth_query<TypeParam>("CREATE ROLE us___er",
|
||||||
false);
|
AuthQuery::Action::CREATE_ROLE, "", "us___er", "",
|
||||||
check_modify_user("ALtEr UsEr dominik", "dominik", std::experimental::nullopt,
|
{}, {});
|
||||||
false);
|
check_auth_query<TypeParam>("CREATE ROLE `us+er`",
|
||||||
check_modify_user("ALtEr UsEr dominik WIth PaSSWORD 'spomenik'", "dominik",
|
AuthQuery::Action::CREATE_ROLE, "", "us+er", "",
|
||||||
"spomenik", false);
|
{}, {});
|
||||||
check_modify_user("ALtEr UsEr dominik WIth PaSSWORD NULL", "dominik",
|
}
|
||||||
TypedValue::Null, false);
|
|
||||||
EXPECT_THROW(
|
TYPED_TEST(CypherMainVisitorTest, CreateRole) {
|
||||||
check_modify_user(
|
ASSERT_THROW(TypeParam("CREATE ROLE"), SyntaxException);
|
||||||
"CreaTE UsEr dominik WIth PaSSWORD 'spomenik' PaSSwoRD 'u muzeju'",
|
check_auth_query<TypeParam>("CREATE ROLE rola",
|
||||||
"dominik", "spomenik", true),
|
AuthQuery::Action::CREATE_ROLE, "", "rola", "",
|
||||||
QueryException);
|
{}, {});
|
||||||
EXPECT_THROW(check_modify_user("CreaTE UsEr dominik WIth PaSSWORD 12345",
|
ASSERT_THROW(TypeParam("CREATE ROLE lagano rolamo"), SyntaxException);
|
||||||
"dominik", "spomenik", true),
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(CypherMainVisitorTest, DropRole) {
|
||||||
|
ASSERT_THROW(TypeParam("DROP ROLE"), SyntaxException);
|
||||||
|
check_auth_query<TypeParam>("DROP ROLE rola", AuthQuery::Action::DROP_ROLE,
|
||||||
|
"", "rola", "", {}, {});
|
||||||
|
ASSERT_THROW(TypeParam("DROP ROLE lagano rolamo"), SyntaxException);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(CypherMainVisitorTest, ShowRoles) {
|
||||||
|
ASSERT_THROW(TypeParam("SHOW ROLES ROLES"), SyntaxException);
|
||||||
|
check_auth_query<TypeParam>("SHOW ROLES", AuthQuery::Action::SHOW_ROLES, "",
|
||||||
|
"", "", {}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(CypherMainVisitorTest, CreateUser) {
|
||||||
|
ASSERT_THROW(TypeParam("CREATE USER"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("CREATE USER 123"), SyntaxException);
|
||||||
|
check_auth_query<TypeParam>("CREATE USER user",
|
||||||
|
AuthQuery::Action::CREATE_USER, "user", "", "",
|
||||||
|
{}, {});
|
||||||
|
check_auth_query<TypeParam>("CREATE USER user IDENTIFIED BY 'password'",
|
||||||
|
AuthQuery::Action::CREATE_USER, "user", "", "",
|
||||||
|
"password", {});
|
||||||
|
check_auth_query<TypeParam>("CREATE USER user IDENTIFIED BY ''",
|
||||||
|
AuthQuery::Action::CREATE_USER, "user", "", "",
|
||||||
|
"", {});
|
||||||
|
check_auth_query<TypeParam>("CREATE USER user IDENTIFIED BY null",
|
||||||
|
AuthQuery::Action::CREATE_USER, "user", "", "",
|
||||||
|
TypedValue::Null, {});
|
||||||
|
ASSERT_THROW(TypeParam("CRATE USER user IDENTIFIED BY password"),
|
||||||
SyntaxException);
|
SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("CREATE USER user IDENTIFIED BY 5"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("CREATE USER user IDENTIFIED BY "), SyntaxException);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(CypherMainVisitorTest, SetPassword) {
|
||||||
|
ASSERT_THROW(TypeParam("SET PASSWORD FOR"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("SET PASSWORD FOR user "), SyntaxException);
|
||||||
|
check_auth_query<TypeParam>("SET PASSWORD FOR user TO null",
|
||||||
|
AuthQuery::Action::SET_PASSWORD, "user", "", "",
|
||||||
|
TypedValue::Null, {});
|
||||||
|
check_auth_query<TypeParam>("SET PASSWORD FOR user TO 'password'",
|
||||||
|
AuthQuery::Action::SET_PASSWORD, "user", "", "",
|
||||||
|
"password", {});
|
||||||
|
ASSERT_THROW(TypeParam("SET PASSWORD FOR user To 5"), SyntaxException);
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST(CypherMainVisitorTest, DropUser) {
|
TYPED_TEST(CypherMainVisitorTest, DropUser) {
|
||||||
auto check_drop_user = [](std::string input,
|
ASSERT_THROW(TypeParam("DROP USER"), SyntaxException);
|
||||||
const std::vector<std::string> &usernames) {
|
check_auth_query<TypeParam>("DROP USER user", AuthQuery::Action::DROP_USER,
|
||||||
TypeParam ast_generator(input);
|
"user", "", "", {}, {});
|
||||||
auto *query = ast_generator.query_;
|
ASSERT_THROW(TypeParam("DROP USER lagano rolamo"), SyntaxException);
|
||||||
ASSERT_TRUE(query->single_query_);
|
}
|
||||||
auto *single_query = query->single_query_;
|
|
||||||
ASSERT_EQ(single_query->clauses_.size(), 1U);
|
|
||||||
auto *drop_user = dynamic_cast<DropUser *>(single_query->clauses_[0]);
|
|
||||||
ASSERT_TRUE(drop_user);
|
|
||||||
EXPECT_EQ(drop_user->usernames_, usernames);
|
|
||||||
};
|
|
||||||
|
|
||||||
EXPECT_THROW(check_drop_user("DrOp USER", {}), SyntaxException);
|
TYPED_TEST(CypherMainVisitorTest, ShowUsers) {
|
||||||
check_drop_user("DrOP UsEr dominik", {"dominik"});
|
ASSERT_THROW(TypeParam("SHOW USERS ROLES"), SyntaxException);
|
||||||
check_drop_user("DrOP USER dominik , spomenik", {"dominik", "spomenik"});
|
check_auth_query<TypeParam>("SHOW USERS", AuthQuery::Action::SHOW_USERS, "",
|
||||||
EXPECT_THROW(
|
"", "", {}, {});
|
||||||
check_drop_user("DrOP USER dominik, , spomenik", {"dominik", "spomenik"}),
|
}
|
||||||
SyntaxException);
|
|
||||||
check_drop_user("DrOP USER dominik , spomenik , jackie, jackie , johnny",
|
TYPED_TEST(CypherMainVisitorTest, GrantRole) {
|
||||||
{"dominik", "spomenik", "jackie", "jackie", "johnny"});
|
ASSERT_THROW(TypeParam("GRANT ROLE"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("GRANT ROLE role"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("GRANT ROLE role TO"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("GRANT ROLE TO user"), SyntaxException);
|
||||||
|
check_auth_query<TypeParam>("GRANT ROLE role TO user",
|
||||||
|
AuthQuery::Action::GRANT_ROLE, "user", "role", "",
|
||||||
|
{}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(CypherMainVisitorTest, RevokeRole) {
|
||||||
|
ASSERT_THROW(TypeParam("REVOKE ROLE"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("REVOKE ROLE role"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("REVOKE ROLE role FROM"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("REVOKE ROLE FROM user"), SyntaxException);
|
||||||
|
check_auth_query<TypeParam>("REVOKE ROLE role FROM user",
|
||||||
|
AuthQuery::Action::REVOKE_ROLE, "user", "role",
|
||||||
|
"", {}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(CypherMainVisitorTest, GrantPrivilege) {
|
||||||
|
ASSERT_THROW(TypeParam("GRANT"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("GRANT TO user"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("GRANT BLABLA TO user"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("GRANT MATCH, TO user"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("GRANT MATCH, BLABLA TO user"), SyntaxException);
|
||||||
|
check_auth_query<TypeParam>("GRANT MATCH TO user",
|
||||||
|
AuthQuery::Action::GRANT_PRIVILEGE, "", "",
|
||||||
|
"user", {}, {AuthQuery::Privilege::MATCH});
|
||||||
|
check_auth_query<TypeParam>(
|
||||||
|
"GRANT MATCH, AUTH TO user", AuthQuery::Action::GRANT_PRIVILEGE, "", "",
|
||||||
|
"user", {}, {AuthQuery::Privilege::MATCH, AuthQuery::Privilege::AUTH});
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(CypherMainVisitorTest, DenyPrivilege) {
|
||||||
|
ASSERT_THROW(TypeParam("DENY"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("DENY TO user"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("DENY BLABLA TO user"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("DENY MATCH, TO user"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("DENY MATCH, BLABLA TO user"), SyntaxException);
|
||||||
|
check_auth_query<TypeParam>("DENY MATCH TO user",
|
||||||
|
AuthQuery::Action::DENY_PRIVILEGE, "", "",
|
||||||
|
"user", {}, {AuthQuery::Privilege::MATCH});
|
||||||
|
check_auth_query<TypeParam>(
|
||||||
|
"DENY MATCH, AUTH TO user", AuthQuery::Action::DENY_PRIVILEGE, "", "",
|
||||||
|
"user", {}, {AuthQuery::Privilege::MATCH, AuthQuery::Privilege::AUTH});
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(CypherMainVisitorTest, RevokePrivilege) {
|
||||||
|
ASSERT_THROW(TypeParam("REVOKE"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("REVOKE FROM user"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("REVOKE BLABLA FROM user"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("REVOKE MATCH, FROM user"), SyntaxException);
|
||||||
|
ASSERT_THROW(TypeParam("REVOKE MATCH, BLABLA FROM user"), SyntaxException);
|
||||||
|
check_auth_query<TypeParam>("REVOKE MATCH FROM user",
|
||||||
|
AuthQuery::Action::REVOKE_PRIVILEGE, "", "",
|
||||||
|
"user", {}, {AuthQuery::Privilege::MATCH});
|
||||||
|
check_auth_query<TypeParam>(
|
||||||
|
"REVOKE MATCH, AUTH FROM user", AuthQuery::Action::REVOKE_PRIVILEGE, "",
|
||||||
|
"", "user", {},
|
||||||
|
{AuthQuery::Privilege::MATCH, AuthQuery::Privilege::AUTH});
|
||||||
|
check_auth_query<TypeParam>(
|
||||||
|
"REVOKE ALL PRIVILEGES FROM user", AuthQuery::Action::REVOKE_PRIVILEGE,
|
||||||
|
"", "", "user", {},
|
||||||
|
{AuthQuery::Privilege::CREATE, AuthQuery::Privilege::DELETE,
|
||||||
|
AuthQuery::Privilege::MATCH, AuthQuery::Privilege::MERGE,
|
||||||
|
AuthQuery::Privilege::SET, AuthQuery::Privilege::AUTH,
|
||||||
|
AuthQuery::Privilege::STREAM});
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(CypherMainVisitorTest, ShowGrants) {
|
||||||
|
ASSERT_THROW(TypeParam("SHOW GRANTS FOR"), SyntaxException);
|
||||||
|
check_auth_query<TypeParam>("SHOW GRANTS FOR user",
|
||||||
|
AuthQuery::Action::SHOW_GRANTS, "", "", "user",
|
||||||
|
{}, {});
|
||||||
|
ASSERT_THROW(TypeParam("SHOW GRANTS FOR user1, user2"), SyntaxException);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(CypherMainVisitorTest, ShowRoleForUser) {
|
||||||
|
ASSERT_THROW(TypeParam("SHOW ROLE FOR USER"), SyntaxException);
|
||||||
|
check_auth_query<TypeParam>("SHOW ROLE FOR USER user",
|
||||||
|
AuthQuery::Action::SHOW_ROLE_FOR_USER, "user", "",
|
||||||
|
"", {}, {});
|
||||||
|
ASSERT_THROW(TypeParam("SHOW ROLE FOR USER user1, user2"), SyntaxException);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(CypherMainVisitorTest, ShowUsersForRole) {
|
||||||
|
ASSERT_THROW(TypeParam("SHOW USERS FOR ROLE"), SyntaxException);
|
||||||
|
check_auth_query<TypeParam>("SHOW USERS FOR ROLE role",
|
||||||
|
AuthQuery::Action::SHOW_USERS_FOR_ROLE, "",
|
||||||
|
"role", "", {}, {});
|
||||||
|
ASSERT_THROW(TypeParam("SHOW USERS FOR ROLE role1, role2"), SyntaxException);
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST(CypherMainVisitorTest, CreateStream) {
|
TYPED_TEST(CypherMainVisitorTest, CreateStream) {
|
||||||
|
@ -574,10 +574,9 @@ auto GetMerge(AstStorage &storage, Pattern *pattern, OnMatch on_match,
|
|||||||
#define EXTRACT(variable, list, expr) \
|
#define EXTRACT(variable, list, expr) \
|
||||||
storage.Create<query::Extract>(storage.Create<query::Identifier>(variable), \
|
storage.Create<query::Extract>(storage.Create<query::Identifier>(variable), \
|
||||||
list, expr)
|
list, expr)
|
||||||
#define CREATE_USER(username, password) \
|
#define AUTH_QUERY(action, user, role, user_or_role, password, privileges) \
|
||||||
storage.Create<query::ModifyUser>((username), LITERAL(password), true)
|
storage.Create<query::AuthQuery>((action), (user), (role), (user_or_role), \
|
||||||
#define ALTER_USER(username, password) \
|
LITERAL(password), (privileges))
|
||||||
storage.Create<query::ModifyUser>((username), LITERAL(password), false)
|
|
||||||
#define DROP_USER(usernames) storage.Create<query::DropUser>((usernames))
|
#define DROP_USER(usernames) storage.Create<query::DropUser>((usernames))
|
||||||
#define CREATE_STREAM(stream_name, stream_uri, stream_topic, transform_uri, \
|
#define CREATE_STREAM(stream_name, stream_uri, stream_topic, transform_uri, \
|
||||||
batch_interval, batch_size) \
|
batch_interval, batch_size) \
|
||||||
|
@ -132,8 +132,7 @@ class PlanChecker : public HierarchicalLogicalOperatorVisitor {
|
|||||||
|
|
||||||
PRE_VISIT(PullRemoteOrderBy);
|
PRE_VISIT(PullRemoteOrderBy);
|
||||||
|
|
||||||
VISIT(ModifyUser);
|
VISIT(AuthHandler);
|
||||||
VISIT(DropUser);
|
|
||||||
|
|
||||||
VISIT(CreateStream);
|
VISIT(CreateStream);
|
||||||
VISIT(DropStream);
|
VISIT(DropStream);
|
||||||
@ -377,6 +376,37 @@ class ExpectScanAllByLabelPropertyRange
|
|||||||
std::experimental::optional<Bound> upper_bound_;
|
std::experimental::optional<Bound> upper_bound_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ExpectAuthHandler : public OpChecker<AuthHandler> {
|
||||||
|
public:
|
||||||
|
ExpectAuthHandler(query::AuthQuery::Action action, std::string user,
|
||||||
|
std::string role, std::string user_or_role,
|
||||||
|
query::Expression *password,
|
||||||
|
std::vector<query::AuthQuery::Privilege> privileges)
|
||||||
|
: action_(action),
|
||||||
|
user_(user),
|
||||||
|
role_(role),
|
||||||
|
user_or_role_(user_or_role),
|
||||||
|
password_(password),
|
||||||
|
privileges_(privileges) {}
|
||||||
|
|
||||||
|
void ExpectOp(AuthHandler &auth_handler, const SymbolTable &) override {
|
||||||
|
EXPECT_EQ(auth_handler.action(), action_);
|
||||||
|
EXPECT_EQ(auth_handler.user(), user_);
|
||||||
|
EXPECT_EQ(auth_handler.role(), role_);
|
||||||
|
EXPECT_EQ(auth_handler.user_or_role(), user_or_role_);
|
||||||
|
EXPECT_TRUE(auth_handler.password());
|
||||||
|
EXPECT_EQ(auth_handler.privileges(), privileges_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
query::AuthQuery::Action action_;
|
||||||
|
std::string user_;
|
||||||
|
std::string role_;
|
||||||
|
std::string user_or_role_;
|
||||||
|
query::Expression *password_{nullptr};
|
||||||
|
std::vector<query::AuthQuery::Privilege> privileges_;
|
||||||
|
};
|
||||||
|
|
||||||
class ExpectCreateIndex : public OpChecker<CreateIndex> {
|
class ExpectCreateIndex : public OpChecker<CreateIndex> {
|
||||||
public:
|
public:
|
||||||
ExpectCreateIndex(storage::Label label, storage::Property property)
|
ExpectCreateIndex(storage::Label label, storage::Property property)
|
||||||
@ -623,36 +653,6 @@ class Planner {
|
|||||||
std::unique_ptr<LogicalOperator> plan_;
|
std::unique_ptr<LogicalOperator> plan_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExpectModifyUser : public OpChecker<ModifyUser> {
|
|
||||||
public:
|
|
||||||
ExpectModifyUser(std::string username, bool is_create)
|
|
||||||
: username_(username), is_create_(is_create) {}
|
|
||||||
|
|
||||||
void ExpectOp(ModifyUser &modify_user, const SymbolTable &) override {
|
|
||||||
EXPECT_EQ(username_, modify_user.username());
|
|
||||||
// TODO(mtomic): proper password verification
|
|
||||||
EXPECT_NE(dynamic_cast<query::Expression *>(modify_user.password()),
|
|
||||||
nullptr);
|
|
||||||
EXPECT_EQ(is_create_, modify_user.is_create());
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string username_;
|
|
||||||
bool is_create_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpectDropUser : public OpChecker<DropUser> {
|
|
||||||
public:
|
|
||||||
ExpectDropUser(std::vector<std::string> usernames) : usernames_(usernames) {}
|
|
||||||
|
|
||||||
void ExpectOp(DropUser &drop_user, const SymbolTable &) override {
|
|
||||||
EXPECT_EQ(usernames_, drop_user.usernames());
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<std::string> usernames_;
|
|
||||||
};
|
|
||||||
|
|
||||||
void SavePlan(const LogicalOperator &plan, ::capnp::MessageBuilder *message) {
|
void SavePlan(const LogicalOperator &plan, ::capnp::MessageBuilder *message) {
|
||||||
auto builder = message->initRoot<query::plan::capnp::LogicalOperator>();
|
auto builder = message->initRoot<query::plan::capnp::LogicalOperator>();
|
||||||
LogicalOperator::SaveHelper helper;
|
LogicalOperator::SaveHelper helper;
|
||||||
@ -2076,8 +2076,9 @@ TYPED_TEST(TestPlanner, WhereIndexedLabelPropertyRange) {
|
|||||||
AstStorage storage;
|
AstStorage storage;
|
||||||
auto lit_42 = LITERAL(42);
|
auto lit_42 = LITERAL(42);
|
||||||
auto n_prop = PROPERTY_LOOKUP("n", property);
|
auto n_prop = PROPERTY_LOOKUP("n", property);
|
||||||
auto check_planned_range = [&label, &property, &dba](
|
auto check_planned_range = [&label, &property, &dba](const auto &rel_expr,
|
||||||
const auto &rel_expr, auto lower_bound, auto upper_bound) {
|
auto lower_bound,
|
||||||
|
auto upper_bound) {
|
||||||
// Shadow the first storage, so that the query is created in this one.
|
// Shadow the first storage, so that the query is created in this one.
|
||||||
AstStorage storage;
|
AstStorage storage;
|
||||||
QUERY(SINGLE_QUERY(MATCH(PATTERN(NODE("n", label))), WHERE(rel_expr),
|
QUERY(SINGLE_QUERY(MATCH(PATTERN(NODE("n", label))), WHERE(rel_expr),
|
||||||
@ -2318,36 +2319,25 @@ TYPED_TEST(TestPlanner, ReturnAsteriskOmitsLambdaSymbols) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST(TestPlanner, ModifyUser) {
|
TYPED_TEST(TestPlanner, AuthQuery) {
|
||||||
{
|
// Check if everything is properly forwarded from ast node to the operator
|
||||||
// Test CREATE USER user WITH PASSWORD 'password'
|
FakeDbAccessor dba;
|
||||||
FakeDbAccessor dba;
|
|
||||||
AstStorage storage;
|
|
||||||
QUERY(SINGLE_QUERY(CREATE_USER("user", "password")));
|
|
||||||
CheckPlan<TypeParam>(storage, ExpectModifyUser("user", true));
|
|
||||||
auto expected =
|
|
||||||
ExpectDistributed(MakeCheckers(ExpectModifyUser("user", true)));
|
|
||||||
CheckDistributedPlan<TypeParam>(storage, expected);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
// Test ALTER USER user WITH PASSWORD 'password'
|
|
||||||
FakeDbAccessor dba;
|
|
||||||
AstStorage storage;
|
|
||||||
QUERY(SINGLE_QUERY(ALTER_USER("user", "password")));
|
|
||||||
CheckPlan<TypeParam>(storage, ExpectModifyUser("user", false));
|
|
||||||
auto expected =
|
|
||||||
ExpectDistributed(MakeCheckers(ExpectModifyUser("user", false)));
|
|
||||||
CheckDistributedPlan<TypeParam>(storage, expected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPED_TEST(TestPlanner, DropUser) {
|
|
||||||
// Test DROP USER user1, user2, user3
|
|
||||||
AstStorage storage;
|
AstStorage storage;
|
||||||
std::vector<std::string> usernames({"user1", "user2", "user3"});
|
QUERY(SINGLE_QUERY(AUTH_QUERY(query::AuthQuery::Action::DROP_ROLE, "user",
|
||||||
QUERY(SINGLE_QUERY(DROP_USER(usernames)));
|
"role", "user_or_role", LITERAL("password"),
|
||||||
CheckPlan<TypeParam>(storage, ExpectDropUser(usernames));
|
std::vector<query::AuthQuery::Privilege>(
|
||||||
auto expected = ExpectDistributed(MakeCheckers(ExpectDropUser(usernames)));
|
{query::AuthQuery::Privilege::MATCH,
|
||||||
|
query::AuthQuery::Privilege::AUTH}))));
|
||||||
|
CheckPlan<TypeParam>(
|
||||||
|
storage, ExpectAuthHandler(query::AuthQuery::Action::DROP_ROLE, "user",
|
||||||
|
"role", "user_or_role", LITERAL("password"),
|
||||||
|
{query::AuthQuery::Privilege::MATCH,
|
||||||
|
query::AuthQuery::Privilege::AUTH}));
|
||||||
|
auto expected = ExpectDistributed(MakeCheckers(
|
||||||
|
ExpectAuthHandler(query::AuthQuery::Action::DROP_ROLE, "user", "role",
|
||||||
|
"user_or_role", LITERAL("password"),
|
||||||
|
{query::AuthQuery::Privilege::MATCH,
|
||||||
|
query::AuthQuery::Privilege::AUTH})));
|
||||||
CheckDistributedPlan<TypeParam>(storage, expected);
|
CheckDistributedPlan<TypeParam>(storage, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user