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:
Marin Tomic 2018-08-06 15:16:39 +02:00
parent ce306a4c21
commit 2a5fce8464
22 changed files with 1106 additions and 510 deletions

View File

@ -132,14 +132,13 @@ struct Clause {
merge @10 :Merge;
unwind @11 :Unwind;
createIndex @12 :CreateIndex;
modifyUser @13 :ModifyUser;
dropUser @14 :DropUser;
createStream @15 :CreateStream;
dropStream @16 :DropStream;
showStreams @17 :ShowStreams;
startStopStream @18 :StartStopStream;
startStopAllStreams @19 :StartStopAllStreams;
testStream @20 :TestStream;
authQuery @13 :AuthQuery;
createStream @14 :CreateStream;
dropStream @15 :DropStream;
showStreams @16 :ShowStreams;
startStopStream @17 :StartStopStream;
startStopAllStreams @18 :StartStopAllStreams;
testStream @19 :TestStream;
}
}
@ -398,14 +397,39 @@ struct CreateIndex {
property @1 :Storage.Common;
}
struct ModifyUser {
username @0 :Text;
password @1 :Tree;
isCreate @2 :Bool;
}
struct DropUser {
usernames @0 :List(Text);
struct AuthQuery {
enum Action {
createRole @0;
dropRole @1;
showRoles @2;
createUser @3;
setPassword @4;
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 {

View File

@ -1268,13 +1268,9 @@ Clause *Clause::Construct(const capnp::Clause::Reader &reader,
auto with_reader = reader.getWith();
return With::Construct(with_reader, storage);
}
case capnp::Clause::MODIFY_USER: {
auto mu_reader = reader.getModifyUser();
return ModifyUser::Construct(mu_reader, storage);
}
case capnp::Clause::DROP_USER: {
auto du_reader = reader.getDropUser();
return DropUser::Construct(du_reader, storage);
case capnp::Clause::AUTH_QUERY: {
auto aq_reader = reader.getAuthQuery();
return AuthQuery::Construct(aq_reader, storage);
}
case capnp::Clause::CREATE_STREAM: {
auto cs_reader = reader.getCreateStream();
@ -2067,69 +2063,188 @@ With *With::Construct(const capnp::With::Reader &reader, AstStorage *storage) {
return storage->Create<With>();
}
// ModifyUser.
void ModifyUser::Save(capnp::Clause::Builder *clause_builder,
std::vector<int> *saved_uids) {
// AuthQuery.
void AuthQuery::Save(capnp::Clause::Builder *clause_builder,
std::vector<int> *saved_uids) {
Clause::Save(clause_builder, saved_uids);
auto builder = clause_builder->initModifyUser();
ModifyUser::Save(&builder, saved_uids);
auto builder = clause_builder->initAuthQuery();
AuthQuery::Save(&builder, saved_uids);
}
void ModifyUser::Save(capnp::ModifyUser::Builder *builder,
std::vector<int> *saved_uids) {
builder->setUsername(username_);
void AuthQuery::Save(capnp::AuthQuery::Builder *builder,
std::vector<int> *saved_uids) {
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_) {
auto password_builder = builder->getPassword();
auto password_builder = builder->initPassword();
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,
AstStorage *storage, std::vector<int> *loaded_uids) {
void AuthQuery::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().getModifyUser();
username_ = reader.getUsername();
if (reader.hasPassword()) {
const auto password_reader = reader.getPassword();
auto auth_reader = base_reader.getClause().getAuthQuery();
switch (auth_reader.getAction()) {
case capnp::AuthQuery::Action::CREATE_ROLE:
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_ =
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,
AstStorage *storage) {
return storage->Create<ModifyUser>();
}
// 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>();
AuthQuery *AuthQuery::Construct(const capnp::AuthQuery::Reader &reader,
AstStorage *storage) {
return storage->Create<AuthQuery>();
}
// CypherUnion

View File

@ -2339,68 +2339,67 @@ class CreateIndex : public Clause {
std::vector<int> *saved_uids);
};
class ModifyUser : public Clause {
class AuthQuery : public Clause {
friend class AstStorage;
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(HierarchicalTreeVisitor);
ModifyUser *Clone(AstStorage &storage) const override {
return storage.Create<ModifyUser>(
username_, password_ ? password_->Clone(storage) : nullptr, is_create_);
AuthQuery *Clone(AstStorage &storage) const override {
return storage.Create<AuthQuery>(
action_, user_, role_, user_or_role_,
password_ ? password_->Clone(storage) : nullptr, privileges_);
}
static ModifyUser *Construct(const capnp::ModifyUser::Reader &reader,
AstStorage *storage);
static AuthQuery *Construct(const capnp::AuthQuery::Reader &reader,
AstStorage *storage);
using Clause::Save;
std::string username_;
Expression *password_;
bool is_create_;
protected:
explicit ModifyUser(int uid) : Clause(uid) {}
ModifyUser(int uid, std::string username, Expression *password,
bool is_create)
explicit AuthQuery(int uid) : Clause(uid) {}
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),
username_(std::move(username)),
action_(action),
user_(user),
role_(role),
user_or_role_(user_or_role),
password_(password),
is_create_(is_create) {}
privileges_(privileges) {}
void Save(capnp::Clause::Builder *builder,
std::vector<int> *saved_uids) override;
virtual void Save(capnp::ModifyUser::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,
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;

View File

@ -61,8 +61,7 @@ class RemoveLabels;
class Merge;
class Unwind;
class CreateIndex;
class ModifyUser;
class DropUser;
class AuthQuery;
class CreateStream;
class DropStream;
class ShowStreams;
@ -84,9 +83,9 @@ using TreeCompositeVisitor = ::utils::CompositeVisitor<
using TreeLeafVisitor =
::utils::LeafVisitor<Identifier, PrimitiveLiteral, ParameterLookup,
CreateIndex, ModifyUser, DropUser, CreateStream,
DropStream, ShowStreams, StartStopStream,
StartStopAllStreams, TestStream>;
CreateIndex, AuthQuery, CreateStream, DropStream,
ShowStreams, StartStopStream, StartStopAllStreams,
TestStream>;
class HierarchicalTreeVisitor : public TreeCompositeVisitor,
public TreeLeafVisitor {
@ -109,8 +108,7 @@ using TreeVisitor = ::utils::Visitor<
Aggregation, Function, Reduce, Extract, All, Single, ParameterLookup,
Create, Match, Return, With, Pattern, NodeAtom, EdgeAtom, Delete, Where,
SetProperty, SetProperties, SetLabels, RemoveProperty, RemoveLabels, Merge,
Unwind, Identifier, PrimitiveLiteral, CreateIndex, ModifyUser, DropUser,
CreateStream, DropStream, ShowStreams, StartStopStream, StartStopAllStreams,
TestStream>;
Unwind, Identifier, PrimitiveLiteral, CreateIndex, AuthQuery, CreateStream,
DropStream, ShowStreams, StartStopStream, StartStopAllStreams, TestStream>;
} // namespace query

View File

@ -5,6 +5,7 @@
#include <codecvt>
#include <cstring>
#include <limits>
#include <regex>
#include <string>
#include <tuple>
#include <unordered_map>
@ -28,13 +29,10 @@ antlrcpp::Any CypherMainVisitor::visitAuthQuery(
MemgraphCypher::AuthQueryContext *ctx) {
query_ = storage_.query();
query_->single_query_ = storage_.Create<SingleQuery>();
Clause *clause = nullptr;
if (ctx->modifyUser()) {
clause = ctx->modifyUser()->accept(this).as<ModifyUser *>();
} else if (ctx->dropUser()) {
clause = ctx->dropUser()->accept(this).as<DropUser *>();
}
query_->single_query_->clauses_ = {clause};
CHECK(ctx->children.size() == 1)
<< "AuthQuery should have exactly one child!";
query_->single_query_->clauses_.push_back(
ctx->children[0]->accept(this).as<AuthQuery *>());
return query_;
}
@ -259,46 +257,224 @@ antlrcpp::Any CypherMainVisitor::visitCreateIndex(
}
/**
* @return ModifyUser*
* @return std::string
*/
antlrcpp::Any CypherMainVisitor::visitModifyUser(
MemgraphCypher::ModifyUserContext *ctx) {
std::string username(ctx->userName->getText());
Expression *password = nullptr;
bool is_create = static_cast<bool>(ctx->CREATE());
for (auto option : ctx->modifyUserOption()) {
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.";
antlrcpp::Any CypherMainVisitor::visitUserOrRoleName(
MemgraphCypher::UserOrRoleNameContext *ctx) {
std::string value = ctx->symbolicName()->accept(this).as<std::string>();
const std::regex NAME_REGEX("[a-zA-Z0-9_.+-]+");
if (!std::regex_match(value, NAME_REGEX)) {
throw SyntaxException("invalid user or role name");
}
return storage_.Create<ModifyUser>(username, password, is_create);
return value;
}
/**
* @return Expression*
* @return AuthQuery*
*/
antlrcpp::Any CypherMainVisitor::visitPasswordOption(
MemgraphCypher::PasswordOptionContext *ctx) {
if (!ctx->literal()->StringLiteral() && !ctx->literal()->CYPHERNULL()) {
antlrcpp::Any CypherMainVisitor::visitCreateRole(
MemgraphCypher::CreateRoleContext *ctx) {
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");
}
return ctx->literal()->accept(this);
auth->password_ = ctx->password->accept(this);
return auth;
}
/**
* @return DropUser*
* @return AuthQuery*
*/
antlrcpp::Any CypherMainVisitor::visitDropUser(
MemgraphCypher::DropUserContext *ctx) {
std::vector<std::string> usernames;
for (auto username_ptr : ctx->userName)
usernames.emplace_back(username_ptr->getText());
return storage_.Create<DropUser>(usernames);
AuthQuery *auth = storage_.Create<AuthQuery>();
auth->action_ = AuthQuery::Action::DROP_USER;
auth->user_ = ctx->user->accept(this).as<std::string>();
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;
}
/**

View File

@ -177,6 +177,28 @@ class CypherMainVisitor : public antlropencypher::MemgraphCypherBaseVisitor {
*/
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*
*/
@ -184,19 +206,79 @@ class CypherMainVisitor : public antlropencypher::MemgraphCypherBaseVisitor {
MemgraphCypher::CreateIndexContext *ctx) override;
/**
* @return ModifyUser*
* @return AuthQuery*
*/
antlrcpp::Any visitModifyUser(
MemgraphCypher::ModifyUserContext *ctx) override;
antlrcpp::Any visitPasswordOption(
MemgraphCypher::PasswordOptionContext *ctx) override;
antlrcpp::Any visitCreateUser(
MemgraphCypher::CreateUserContext *ctx) override;
/**
* @return DropUser*
* @return AuthQuery*
*/
antlrcpp::Any visitSetPassword(
MemgraphCypher::SetPasswordContext *ctx) override;
/**
* @return AuthQuery*
*/
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*
*/

View File

@ -8,23 +8,36 @@ import Cypher ;
memgraphCypherKeyword : cypherKeyword
| ALTER
| AUTH
| BATCH
| BATCHES
| DATA
| DENY
| DROP
| FOR
| FROM
| GRANT
| GRANTS
| IDENTIFIED
| INTERVAL
| K_TEST
| KAFKA
| LOAD
| PASSWORD
| PRIVILEGES
| REVOKE
| ROLE
| ROLES
| SIZE
| START
| STOP
| STREAM
| STREAMS
| TO
| TOPIC
| TRANSFORM
| USER
| USERS
;
symbolicName : UnescapedSymbolicName
@ -37,19 +50,60 @@ query : regularQuery
| streamQuery
;
authQuery : modifyUser
authQuery : createRole
| dropRole
| showRoles
| createUser
| setPassword
| dropUser
| showUsers
| grantRole
| revokeRole
| grantPrivilege
| denyPrivilege
| revokePrivilege
| showGrants
| showRoleForUser
| showUsersForRole
;
modifyUser : ( CREATE | ALTER ) USER userName=UnescapedSymbolicName
( WITH ( modifyUserOption )+ )? ;
userOrRoleName : symbolicName ;
modifyUserOption : passwordOption ;
createRole : CREATE ROLE role=userOrRoleName ;
passwordOption : PASSWORD literal;
dropRole : DROP ROLE role=userOrRoleName ;
dropUser : DROP USER userName+=UnescapedSymbolicName
( ',' userName+=UnescapedSymbolicName )* ;
showRoles : SHOW ROLES ;
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
| dropStream

View File

@ -11,20 +11,33 @@ lexer grammar MemgraphCypherLexer ;
import CypherLexer ;
ALTER : A L T E R ;
AUTH : A U T H ;
BATCH : B A T C H ;
BATCHES : B A T C H E S ;
DATA : D A T A ;
DENY : D E N Y ;
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 ;
K_TEST : T E S T ;
KAFKA : K A F K A ;
LOAD : L O A 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 ;
START : S T A R T ;
STOP : S T O P ;
STREAM : S T R E A M ;
STREAMS : S T R E A M S ;
TO : T O ;
TOPIC : T O P I C ;
TRANSFORM : T R A N S F O R M ;
USER : U S E R ;
USERS : U S E R S ;

View File

@ -220,9 +220,7 @@ bool SymbolGenerator::PostVisit(Match &) {
bool SymbolGenerator::Visit(CreateIndex &) { return true; }
bool SymbolGenerator::Visit(ModifyUser &) { return true; }
bool SymbolGenerator::Visit(DropUser &) { return true; }
bool SymbolGenerator::Visit(AuthQuery &) { return true; }
bool SymbolGenerator::Visit(CreateStream &) { return true; }

View File

@ -47,8 +47,7 @@ class SymbolGenerator : public HierarchicalTreeVisitor {
bool PreVisit(Match &) override;
bool PostVisit(Match &) override;
bool Visit(CreateIndex &) override;
bool Visit(ModifyUser &) override;
bool Visit(DropUser &) override;
bool Visit(AuthQuery &) override;
bool Visit(CreateStream &) override;
bool Visit(DropStream &) override;
bool Visit(ShowStreams &) override;

View File

@ -49,8 +49,7 @@ class ExpressionEvaluator : public TreeVisitor<TypedValue> {
BLOCK_VISIT(Merge);
BLOCK_VISIT(Unwind);
BLOCK_VISIT(CreateIndex);
BLOCK_VISIT(ModifyUser);
BLOCK_VISIT(DropUser);
BLOCK_VISIT(AuthQuery);
BLOCK_VISIT(CreateStream);
BLOCK_VISIT(DropStream);
BLOCK_VISIT(ShowStreams);

View File

@ -185,8 +185,7 @@ class CostEstimator : public HierarchicalLogicalOperatorVisitor {
bool Visit(Once &) override { return true; }
bool Visit(CreateIndex &) override { return true; }
bool Visit(ModifyUser &) override { return true; }
bool Visit(DropUser &) override { return true; }
bool Visit(AuthHandler &) override { return true; }
bool Visit(CreateStream &) override { return true; }
bool Visit(DropStream &) override { return true; }
bool Visit(ShowStreams &) override { return true; }

View File

@ -87,8 +87,7 @@ class IndependentSubtreeFinder : public HierarchicalLogicalOperatorVisitor {
// These don't use any symbols
bool Visit(Once &) override { return true; }
bool Visit(CreateIndex &) override { return true; }
bool Visit(ModifyUser &) override { return true; }
bool Visit(DropUser &) override { return true; }
bool Visit(AuthHandler &) override { return true; }
bool Visit(CreateStream &) override { return true; }
bool Visit(DropStream &) 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(ModifyUser &) override { return true; }
bool Visit(DropUser &) override { return true; }
bool Visit(AuthHandler &) override { return true; }
bool Visit(CreateStream &) override { return true; }

View File

@ -159,7 +159,7 @@ VertexAccessor &CreateVertexOnWorker(int worker_id, NodeAtom *node_atom,
int current_worker_id = 0;
// TODO: Figure out a better solution.
if (auto *distributed_db =
dynamic_cast<database::DistributedGraphDb *>(&dba.db())) {
dynamic_cast<database::DistributedGraphDb *>(&dba.db())) {
current_worker_id = distributed_db->WorkerId();
} else {
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
// satisfy the "where" condition. if so, places them in the priority queue.
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(vertex, self_.graph_view_);
@ -3889,130 +3890,120 @@ std::unique_ptr<Cursor> PullRemoteOrderBy::MakeCursor(
return std::make_unique<PullRemoteOrderByCursor>(*this, db);
}
ModifyUser::ModifyUser(std::string username, Expression *password,
bool is_create)
: username_(std::move(username)),
AuthHandler::AuthHandler(AuthQuery::Action action, std::string user,
std::string role, std::string user_or_role,
Expression *password,
std::vector<AuthQuery::Privilege> privileges)
: action_(action),
user_(user),
role_(role),
user_or_role_(user_or_role),
password_(password),
is_create_(is_create) {}
privileges_(privileges) {}
bool ModifyUser::Accept(HierarchicalLogicalOperatorVisitor &visitor) {
bool AuthHandler::Accept(HierarchicalLogicalOperatorVisitor &visitor) {
return visitor.Visit(*this);
}
WITHOUT_SINGLE_INPUT(ModifyUser)
class ModifyUserCursor : public Cursor {
class AuthHandlerCursor : public Cursor {
public:
ModifyUserCursor(const ModifyUser &self) : self_(self) {}
AuthHandlerCursor(const AuthHandler &self) : self_(self) {}
bool Pull(Frame &frame, Context &ctx) override {
if (ctx.in_explicit_transaction_) {
throw UserModificationInMulticommandTxException();
}
ExpressionEvaluator evaluator(frame, &ctx, GraphView::OLD);
TypedValue password_tv = self_.password()->Accept(evaluator);
if (password_tv.type() != TypedValue::Type::String) {
throw QueryRuntimeException(fmt::format(
"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()));
std::experimental::optional<std::string> password;
/* TODO(mferencevic): handle null passwords properly */
if (self_.password()) {
auto password_tv = self_.password()->Accept(evaluator);
if (!password_tv.IsString()) {
throw QueryRuntimeException("Password must be a string, not '{}'!",
password_tv.type());
}
} else {
// Update an existing user.
user = ctx.auth_->GetUser(self_.username());
if (!user) {
throw QueryRuntimeException(
fmt::format("User '{}' doesn't exist!", self_.username()));
password = password_tv.ValueString();
}
auto &auth = *ctx.auth_;
std::lock_guard<std::mutex> lock(auth.WithLock());
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;
}
void Reset() override {}
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 {
LOG(FATAL) << "AuthHandler cursor should never be reset";
}
void Reset() override {}
private:
const DropUser &self_;
const AuthHandler &self_;
};
std::unique_ptr<Cursor> DropUser::MakeCursor(
database::GraphDbAccessor &) const {
return std::make_unique<DropUserCursor>(*this);
std::unique_ptr<Cursor> AuthHandler::MakeCursor(
database::GraphDbAccessor &db) const {
return std::make_unique<AuthHandlerCursor>(*this);
}
WITHOUT_SINGLE_INPUT(AuthHandler)
CreateStream::CreateStream(std::string stream_name, Expression *stream_uri,
Expression *stream_topic, Expression *transform_uri,
Expression *batch_interval_in_ms,

View File

@ -102,8 +102,7 @@ class PullRemote;
class Synchronize;
class Cartesian;
class PullRemoteOrderBy;
class ModifyUser;
class DropUser;
class AuthHandler;
class CreateStream;
class DropStream;
class ShowStreams;
@ -122,9 +121,9 @@ using LogicalOperatorCompositeVisitor = ::utils::CompositeVisitor<
Cartesian, PullRemoteOrderBy>;
using LogicalOperatorLeafVisitor =
::utils::LeafVisitor<Once, CreateIndex, ModifyUser, DropUser,
CreateStream, DropStream, ShowStreams,
StartStopStream, StartStopAllStreams, TestStream>;
::utils::LeafVisitor<Once, CreateIndex, AuthHandler, CreateStream,
DropStream, ShowStreams, StartStopStream,
StartStopAllStreams, TestStream>;
/**
* @brief Base class for hierarhical visitors of @c LogicalOperator class
@ -1969,6 +1968,114 @@ and returns true, once.")
cpp<#)
(: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)
((input "std::shared_ptr<LogicalOperator>"
: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;
std::vector<Symbol> ModifiedSymbols(const SymbolTable &) const override;
bool HasSingleInput() const override { return true; }
std::shared_ptr<LogicalOperator> input() const override { return input_; }
bool HasSingleInput() const override {
return true; }
std::shared_ptr<LogicalOperator> input() const override {
return input_; }
void set_input(std::shared_ptr<LogicalOperator> input) override {
input_ = input;
}
@ -2338,70 +2447,6 @@ by having only one result from each worker.")
(:private #>cpp PullRemoteOrderBy() {} cpp<#)
(: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)
((stream-name "std::string" :reader t)
(stream-uri "Expression *"

View File

@ -53,8 +53,7 @@ class UsedSymbolsCollector : public HierarchicalTreeVisitor {
bool Visit(PrimitiveLiteral &) override { return true; }
bool Visit(ParameterLookup &) override { return true; }
bool Visit(query::CreateIndex &) override { return true; }
bool Visit(query::ModifyUser &) override { return true; }
bool Visit(query::DropUser &) override { return true; }
bool Visit(query::AuthQuery &) override { return true; }
bool Visit(query::CreateStream &) override { return true; }
bool Visit(query::DropStream &) override { return true; }
bool Visit(query::ShowStreams &) override { return true; }

View File

@ -402,12 +402,7 @@ class ReturnBodyContext : public HierarchicalTreeVisitor {
return true;
}
bool Visit(query::ModifyUser &) override {
has_aggregation_.emplace_back(false);
return true;
}
bool Visit(query::DropUser &) override {
bool Visit(query::AuthQuery &) override {
has_aggregation_.emplace_back(false);
return true;
}

View File

@ -182,15 +182,13 @@ class RuleBasedPlanner {
DCHECK(!input_op) << "Unexpected operator before CreateIndex";
input_op = std::make_unique<plan::CreateIndex>(
create_index->label_, create_index->property_);
} else if (auto *modify_user =
dynamic_cast<query::ModifyUser *>(clause)) {
DCHECK(!input_op) << "Unexpected operator before ModifyUser";
input_op = std::make_unique<plan::ModifyUser>(
modify_user->username_, modify_user->password_,
modify_user->is_create_);
} else if (auto *drop_user = dynamic_cast<query::DropUser *>(clause)) {
DCHECK(!input_op) << "Unexpected operator before DropUser";
input_op = std::make_unique<plan::DropUser>(drop_user->usernames_);
} else if (auto *auth_query =
dynamic_cast<query::AuthQuery *>(clause)) {
DCHECK(!input_op) << "Unexpected operator before AuthQuery";
input_op = std::make_unique<plan::AuthHandler>(
auth_query->action_, auth_query->user_, auth_query->role_,
auth_query->user_or_role_, auth_query->password_,
auth_query->privileges_);
} else if (auto *create_stream =
dynamic_cast<query::CreateStream *>(clause)) {
DCHECK(!input_op) << "Unexpected operator before CreateStream";

View File

@ -514,13 +514,8 @@ class PlanPrinter : public query::plan::HierarchicalLogicalOperatorVisitor {
return true;
}
bool Visit(query::plan::ModifyUser &op) override {
WithPrintLn([](auto &out) { out << "* ModifyUser "; });
return true;
}
bool Visit(query::plan::DropUser &op) override {
WithPrintLn([](auto &out) { out << "* DropUser"; });
bool Visit(query::plan::AuthHandler &op) override {
WithPrintLn([](auto &out) { out << "* AuthHandler"; });
return true;
}

View File

@ -1866,72 +1866,203 @@ TYPED_TEST(CypherMainVisitorTest, UnionAll) {
ASSERT_FALSE(return_clause->body_.distinct);
}
TYPED_TEST(CypherMainVisitorTest, ModifyUser) {
auto check_modify_user = [](std::string input, std::string username,
std::experimental::optional<TypedValue> password,
bool is_create) {
TypeParam ast_generator(input);
auto *query = ast_generator.query_;
ASSERT_TRUE(query->single_query_);
auto *single_query = query->single_query_;
ASSERT_EQ(single_query->clauses_.size(), 1U);
auto *create_user = dynamic_cast<ModifyUser *>(single_query->clauses_[0]);
ASSERT_TRUE(create_user);
EXPECT_EQ(create_user->username_, username);
if (password) {
ASSERT_NE(create_user->password_, nullptr);
CheckLiteral(ast_generator.context_, create_user->password_, *password);
} else {
EXPECT_EQ(create_user->password_, nullptr);
}
EXPECT_EQ(create_user->is_create_, is_create);
};
template <typename AstGeneratorT>
void check_auth_query(std::string input, AuthQuery::Action action,
std::string user, std::string role,
std::string user_or_role,
std::experimental::optional<TypedValue> password,
std::vector<AuthQuery::Privilege> privileges) {
AstGeneratorT ast_generator(input);
auto *query = ast_generator.query_;
ASSERT_TRUE(query->single_query_ &&
query->single_query_->clauses_.size() == 1U);
auto auth_query =
dynamic_cast<AuthQuery *>(query->single_query_->clauses_[0]);
EXPECT_EQ(auth_query->action_, action);
EXPECT_EQ(auth_query->user_, user);
EXPECT_EQ(auth_query->role_, role);
EXPECT_EQ(auth_query->user_or_role_, user_or_role);
ASSERT_EQ(static_cast<bool>(auth_query->password_),
static_cast<bool>(password));
if (password) {
CheckLiteral(ast_generator.context_, auth_query->password_, *password);
}
EXPECT_EQ(auth_query->privileges_, privileges);
}
check_modify_user("CreaTE UsEr dominik", "dominik",
std::experimental::nullopt, true);
check_modify_user("CreaTE UsEr dominik WIth PaSSWORD 'spomenik'", "dominik",
"spomenik", true);
check_modify_user("CreaTE UsEr dominik WIth PaSSWORD NULL", "dominik",
TypedValue::Null, true);
check_modify_user("AlTeR UsEr dominik", "dominik", std::experimental::nullopt,
false);
check_modify_user("ALtEr UsEr dominik", "dominik", std::experimental::nullopt,
false);
check_modify_user("ALtEr UsEr dominik WIth PaSSWORD 'spomenik'", "dominik",
"spomenik", false);
check_modify_user("ALtEr UsEr dominik WIth PaSSWORD NULL", "dominik",
TypedValue::Null, false);
EXPECT_THROW(
check_modify_user(
"CreaTE UsEr dominik WIth PaSSWORD 'spomenik' PaSSwoRD 'u muzeju'",
"dominik", "spomenik", true),
QueryException);
EXPECT_THROW(check_modify_user("CreaTE UsEr dominik WIth PaSSWORD 12345",
"dominik", "spomenik", true),
TYPED_TEST(CypherMainVisitorTest, UserOrRoleName) {
ASSERT_THROW(TypeParam("CREATE ROLE `us|er`"), SyntaxException);
ASSERT_THROW(TypeParam("CREATE ROLE `us er`"), SyntaxException);
check_auth_query<TypeParam>("CREATE ROLE `user`",
AuthQuery::Action::CREATE_ROLE, "", "user", "",
{}, {});
check_auth_query<TypeParam>("CREATE ROLE us___er",
AuthQuery::Action::CREATE_ROLE, "", "us___er", "",
{}, {});
check_auth_query<TypeParam>("CREATE ROLE `us+er`",
AuthQuery::Action::CREATE_ROLE, "", "us+er", "",
{}, {});
}
TYPED_TEST(CypherMainVisitorTest, CreateRole) {
ASSERT_THROW(TypeParam("CREATE ROLE"), SyntaxException);
check_auth_query<TypeParam>("CREATE ROLE rola",
AuthQuery::Action::CREATE_ROLE, "", "rola", "",
{}, {});
ASSERT_THROW(TypeParam("CREATE ROLE lagano rolamo"), SyntaxException);
}
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);
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) {
auto check_drop_user = [](std::string input,
const std::vector<std::string> &usernames) {
TypeParam ast_generator(input);
auto *query = ast_generator.query_;
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);
};
ASSERT_THROW(TypeParam("DROP USER"), SyntaxException);
check_auth_query<TypeParam>("DROP USER user", AuthQuery::Action::DROP_USER,
"user", "", "", {}, {});
ASSERT_THROW(TypeParam("DROP USER lagano rolamo"), SyntaxException);
}
EXPECT_THROW(check_drop_user("DrOp USER", {}), SyntaxException);
check_drop_user("DrOP UsEr dominik", {"dominik"});
check_drop_user("DrOP USER dominik , spomenik", {"dominik", "spomenik"});
EXPECT_THROW(
check_drop_user("DrOP USER dominik, , spomenik", {"dominik", "spomenik"}),
SyntaxException);
check_drop_user("DrOP USER dominik , spomenik , jackie, jackie , johnny",
{"dominik", "spomenik", "jackie", "jackie", "johnny"});
TYPED_TEST(CypherMainVisitorTest, ShowUsers) {
ASSERT_THROW(TypeParam("SHOW USERS ROLES"), SyntaxException);
check_auth_query<TypeParam>("SHOW USERS", AuthQuery::Action::SHOW_USERS, "",
"", "", {}, {});
}
TYPED_TEST(CypherMainVisitorTest, GrantRole) {
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) {

View File

@ -574,10 +574,9 @@ auto GetMerge(AstStorage &storage, Pattern *pattern, OnMatch on_match,
#define EXTRACT(variable, list, expr) \
storage.Create<query::Extract>(storage.Create<query::Identifier>(variable), \
list, expr)
#define CREATE_USER(username, password) \
storage.Create<query::ModifyUser>((username), LITERAL(password), true)
#define ALTER_USER(username, password) \
storage.Create<query::ModifyUser>((username), LITERAL(password), false)
#define AUTH_QUERY(action, user, role, user_or_role, password, privileges) \
storage.Create<query::AuthQuery>((action), (user), (role), (user_or_role), \
LITERAL(password), (privileges))
#define DROP_USER(usernames) storage.Create<query::DropUser>((usernames))
#define CREATE_STREAM(stream_name, stream_uri, stream_topic, transform_uri, \
batch_interval, batch_size) \

View File

@ -132,8 +132,7 @@ class PlanChecker : public HierarchicalLogicalOperatorVisitor {
PRE_VISIT(PullRemoteOrderBy);
VISIT(ModifyUser);
VISIT(DropUser);
VISIT(AuthHandler);
VISIT(CreateStream);
VISIT(DropStream);
@ -377,6 +376,37 @@ class ExpectScanAllByLabelPropertyRange
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> {
public:
ExpectCreateIndex(storage::Label label, storage::Property property)
@ -623,36 +653,6 @@ class Planner {
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) {
auto builder = message->initRoot<query::plan::capnp::LogicalOperator>();
LogicalOperator::SaveHelper helper;
@ -2076,8 +2076,9 @@ TYPED_TEST(TestPlanner, WhereIndexedLabelPropertyRange) {
AstStorage storage;
auto lit_42 = LITERAL(42);
auto n_prop = PROPERTY_LOOKUP("n", property);
auto check_planned_range = [&label, &property, &dba](
const auto &rel_expr, auto lower_bound, auto upper_bound) {
auto check_planned_range = [&label, &property, &dba](const auto &rel_expr,
auto lower_bound,
auto upper_bound) {
// Shadow the first storage, so that the query is created in this one.
AstStorage storage;
QUERY(SINGLE_QUERY(MATCH(PATTERN(NODE("n", label))), WHERE(rel_expr),
@ -2318,36 +2319,25 @@ TYPED_TEST(TestPlanner, ReturnAsteriskOmitsLambdaSymbols) {
}
}
TYPED_TEST(TestPlanner, ModifyUser) {
{
// Test CREATE USER user WITH PASSWORD 'password'
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
TYPED_TEST(TestPlanner, AuthQuery) {
// Check if everything is properly forwarded from ast node to the operator
FakeDbAccessor dba;
AstStorage storage;
std::vector<std::string> usernames({"user1", "user2", "user3"});
QUERY(SINGLE_QUERY(DROP_USER(usernames)));
CheckPlan<TypeParam>(storage, ExpectDropUser(usernames));
auto expected = ExpectDistributed(MakeCheckers(ExpectDropUser(usernames)));
QUERY(SINGLE_QUERY(AUTH_QUERY(query::AuthQuery::Action::DROP_ROLE, "user",
"role", "user_or_role", LITERAL("password"),
std::vector<query::AuthQuery::Privilege>(
{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);
}