Skip to content

Commit

Permalink
describe the user (#3300)
Browse files Browse the repository at this point in the history
* feat: describe the user

* refactor - add syntax desc user xxx

* bug - add permission check

* style - permissionCheck

* fix - user not exist

* test - add tck session and cases

* style - remove annotation

* refact - table style

* feat - compatible with pipe

* fix - merge conflict

* style - format

* feat - tck query by common user

* refact - remove duplicate interfaces

* fix comment
  • Loading branch information
heroicNeZha authored Nov 25, 2021
1 parent c6d1046 commit a14d7b4
Show file tree
Hide file tree
Showing 20 changed files with 301 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/graph/executor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ nebula_add_library(
admin/ChangePasswordExecutor.cpp
admin/ListUserRolesExecutor.cpp
admin/ListUsersExecutor.cpp
admin/DescribeUserExecutor.cpp
admin/ListRolesExecutor.cpp
admin/SubmitJobExecutor.cpp
admin/ShowHostsExecutor.cpp
Expand Down
4 changes: 4 additions & 0 deletions src/graph/executor/Executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "graph/executor/admin/CharsetExecutor.h"
#include "graph/executor/admin/ConfigExecutor.h"
#include "graph/executor/admin/CreateUserExecutor.h"
#include "graph/executor/admin/DescribeUserExecutor.h"
#include "graph/executor/admin/DownloadExecutor.h"
#include "graph/executor/admin/DropUserExecutor.h"
#include "graph/executor/admin/GrantRoleExecutor.h"
Expand Down Expand Up @@ -385,6 +386,9 @@ Executor *Executor::makeExecutor(QueryContext *qctx, const PlanNode *node) {
case PlanNode::Kind::kListRoles: {
return pool->add(new ListRolesExecutor(node, qctx));
}
case PlanNode::Kind::kDescribeUser: {
return pool->add(new DescribeUserExecutor(node, qctx));
}
case PlanNode::Kind::kShowConfigs: {
return pool->add(new ShowConfigsExecutor(node, qctx));
}
Expand Down
57 changes: 57 additions & 0 deletions src/graph/executor/admin/DescribeUserExecutor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/* Copyright (c) 2020 vesoft inc. All rights reserved.
*
* This source code is licensed under Apache 2.0 License.
*/

#include "graph/executor/admin/DescribeUserExecutor.h"

#include <thrift/lib/cpp/util/EnumUtils.h>

#include "graph/context/QueryContext.h"
#include "graph/planner/plan/Admin.h"
#include "interface/gen-cpp2/meta_types.h"

namespace nebula {
namespace graph {

folly::Future<Status> DescribeUserExecutor::execute() {
SCOPED_TIMER(&execTime_);
return describeUser();
}

folly::Future<Status> DescribeUserExecutor::describeUser() {
auto* duNode = asNode<DescribeUser>(node());
return qctx()
->getMetaClient()
->getUserRoles(*duNode->username())
.via(runner())
.thenValue([this](StatusOr<std::vector<meta::cpp2::RoleItem>>&& resp) {
SCOPED_TIMER(&execTime_);
if (!resp.ok()) {
return std::move(resp).status();
}

DataSet v({"role", "space"});
auto roleItemList = std::move(resp).value();
for (auto& item : roleItemList) {
if (item.get_space_id() == 0) {
v.emplace_back(
nebula::Row({apache::thrift::util::enumNameSafe(item.get_role_type()), ""}));
} else {
auto spaceNameResult = qctx_->schemaMng()->toGraphSpaceName(item.get_space_id());
if (spaceNameResult.ok()) {
v.emplace_back(nebula::Row({apache::thrift::util::enumNameSafe(item.get_role_type()),
spaceNameResult.value()}));
} else {
LOG(ERROR) << " Space name of " << item.get_space_id() << " no found";
return Status::Error("Space not found");
}
}
}
return finish(
ResultBuilder().value(Value(std::move(v))).iter(Iterator::Kind::kSequential).build());
});
}

} // namespace graph
} // namespace nebula
28 changes: 28 additions & 0 deletions src/graph/executor/admin/DescribeUserExecutor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* Copyright (c) 2020 vesoft inc. All rights reserved.
*
* This source code is licensed under Apache 2.0 License.
*/

#ifndef GRAPH_EXECUTOR_ADMIN_DESCRIBEUSEREXECUTOR_H_
#define GRAPH_EXECUTOR_ADMIN_DESCRIBEUSEREXECUTOR_H_

#include "graph/executor/Executor.h"

namespace nebula {
namespace graph {

class DescribeUserExecutor final : public Executor {
public:
DescribeUserExecutor(const PlanNode *node, QueryContext *qctx)
: Executor("DescribeUsersExecutor", node, qctx) {}

folly::Future<Status> execute() override;

private:
folly::Future<Status> describeUser();
};

} // namespace graph
} // namespace nebula

#endif // GRAPH_EXECUTOR_ADMIN_LISTUSERSEXECUTOR_H_
6 changes: 6 additions & 0 deletions src/graph/planner/plan/Admin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ std::unique_ptr<PlanNodeDescription> ChangePassword::explain() const {
return desc;
}

std::unique_ptr<PlanNodeDescription> DescribeUser::explain() const {
auto desc = SingleDependencyNode::explain();
addDescription("username", *username_, desc.get());
return desc;
}

std::unique_ptr<PlanNodeDescription> ListUserRoles::explain() const {
auto desc = SingleDependencyNode::explain();
addDescription("username", *username_, desc.get());
Expand Down
17 changes: 17 additions & 0 deletions src/graph/planner/plan/Admin.h
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,23 @@ class ListUsers final : public SingleDependencyNode {
: SingleDependencyNode(qctx, Kind::kListUsers, dep) {}
};

class DescribeUser final : public SingleDependencyNode {
public:
static DescribeUser* make(QueryContext* qctx, PlanNode* dep, const std::string* username) {
return qctx->objPool()->add(new DescribeUser(qctx, dep, username));
}

std::unique_ptr<PlanNodeDescription> explain() const override;

const std::string* username() const { return username_; }

private:
explicit DescribeUser(QueryContext* qctx, PlanNode* dep, const std::string* username)
: SingleDependencyNode(qctx, Kind::kDescribeUser, dep), username_(username) {}

const std::string* username_;
};

class ListRoles final : public SingleDependencyNode {
public:
static ListRoles* make(QueryContext* qctx, PlanNode* dep, GraphSpaceID space) {
Expand Down
2 changes: 2 additions & 0 deletions src/graph/planner/plan/PlanNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ const char* PlanNode::toString(PlanNode::Kind kind) {
return "ListUserRoles";
case Kind::kListUsers:
return "ListUsers";
case Kind::kDescribeUser:
return "DescribeUser";
case Kind::kListRoles:
return "ListRoles";
case Kind::kShowCreateSpace:
Expand Down
1 change: 1 addition & 0 deletions src/graph/planner/plan/PlanNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ class PlanNode {
kListUserRoles,
kListUsers,
kListRoles,
kDescribeUser,

// Snapshot
kCreateSnapshot,
Expand Down
1 change: 1 addition & 0 deletions src/graph/service/PermissionCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ Status PermissionCheck::permissionCheck(ClientSession *session,
case Sentence::Kind::kShowRoles: {
return PermissionManager::canReadSpace(session, targetSpace);
}
case Sentence::Kind::kDescribeUser:
case Sentence::Kind::kShowUsers:
case Sentence::Kind::kShowSnapshots:
case Sentence::Kind::kShowTSClients:
Expand Down
19 changes: 19 additions & 0 deletions src/graph/service/PermissionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,25 @@ Status PermissionManager::canWriteUser(ClientSession *session) {
}
}

// static
Status PermissionManager::canReadUser(ClientSession *session, const std::string &targetUser) {
if (!FLAGS_enable_authorize) {
return Status::OK();
}
if (FLAGS_auth_type == "cloud") {
return Status::PermissionError("Cloud authenticate user can't read user.");
}
if (session->isGod()) {
return Status::OK();
}

if (session->user() == targetUser) {
return Status::OK();
}

return Status::PermissionError("No permission to read user `%s'.", targetUser.c_str());
}

Status PermissionManager::canWriteRole(ClientSession *session,
meta::cpp2::RoleType targetRole,
GraphSpaceID spaceId,
Expand Down
1 change: 1 addition & 0 deletions src/graph/service/PermissionManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class PermissionManager final {
static Status canWriteSpace(ClientSession *session);
static Status canWriteSchema(ClientSession *session, ValidateContext *vctx);
static Status canWriteUser(ClientSession *session);
static Status canReadUser(ClientSession *session, const std::string &targetUser);
static Status canWriteRole(ClientSession *session,
meta::cpp2::RoleType targetRole,
GraphSpaceID spaceId,
Expand Down
25 changes: 25 additions & 0 deletions src/graph/validator/ACLValidator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,31 @@ Status RevokeRoleValidator::toPlan() {
sentence->getAclItemClause()->getRoleType());
}

// describe user
Status DescribeUserValidator::validateImpl() {
auto sentence = static_cast<DescribeUserSentence *>(sentence_);
if (sentence->account()->size() > kUsernameMaxLength) {
return Status::SemanticError("Username exceed maximum length %ld characters.",
kUsernameMaxLength);
}
if (!inputs_.empty()) {
return Status::SemanticError("Show queries sentence do not support input");
}
outputs_.emplace_back("role", Value::Type::STRING);
outputs_.emplace_back("space", Value::Type::STRING);
return Status::OK();
}

Status DescribeUserValidator::checkPermission() {
auto sentence = static_cast<DescribeUserSentence *>(sentence_);
return PermissionManager::canReadUser(qctx_->rctx()->session(), *sentence->account());
}

Status DescribeUserValidator::toPlan() {
auto sentence = static_cast<DescribeUserSentence *>(sentence_);
return genSingleNodePlan<DescribeUser>(sentence->account());
}

// show roles in space
Status ShowRolesInSpaceValidator::validateImpl() {
auto sentence = static_cast<ShowRolesSentence *>(sentence_);
Expand Down
14 changes: 14 additions & 0 deletions src/graph/validator/ACLValidator.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,20 @@ class RevokeRoleValidator final : public Validator {
Status toPlan() override;
};

class DescribeUserValidator final : public Validator {
public:
DescribeUserValidator(Sentence* sentence, QueryContext* context) : Validator(sentence, context) {
setNoSpaceRequired();
}

private:
Status validateImpl() override;

Status checkPermission() override;

Status toPlan() override;
};

class ShowRolesInSpaceValidator final : public Validator {
public:
ShowRolesInSpaceValidator(Sentence* sentence, QueryContext* context)
Expand Down
2 changes: 2 additions & 0 deletions src/graph/validator/Validator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ std::unique_ptr<Validator> Validator::makeValidator(Sentence* sentence, QueryCon
return std::make_unique<RevokeRoleValidator>(sentence, context);
case Sentence::Kind::kShowRoles:
return std::make_unique<ShowRolesInSpaceValidator>(sentence, context);
case Sentence::Kind::kDescribeUser:
return std::make_unique<DescribeUserValidator>(sentence, context);
case Sentence::Kind::kAdminJob:
case Sentence::Kind::kAdminShowJobs:
return std::make_unique<AdminJobValidator>(sentence, context);
Expand Down
4 changes: 4 additions & 0 deletions src/parser/AdminSentences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ std::string ShowPartsSentence::toString() const { return std::string("SHOW PARTS

std::string ShowUsersSentence::toString() const { return std::string("SHOW USERS"); }

std::string DescribeUserSentence::toString() const {
return folly::stringPrintf("DESCRIBE USER %s", account_.get()->c_str());
}

std::string ShowRolesSentence::toString() const {
return folly::stringPrintf("SHOW ROLES IN %s", name_.get()->c_str());
}
Expand Down
15 changes: 15 additions & 0 deletions src/parser/AdminSentences.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,21 @@ class ShowUsersSentence : public Sentence {
std::string toString() const override;
};

class DescribeUserSentence : public Sentence {
public:
explicit DescribeUserSentence(std::string* account) {
account_.reset(account);
kind_ = Kind::kDescribeUser;
}

std::string toString() const override;

const std::string* account() const { return account_.get(); }

private:
std::unique_ptr<std::string> account_;
};

class ShowRolesSentence : public Sentence {
public:
explicit ShowRolesSentence(std::string* name) {
Expand Down
1 change: 1 addition & 0 deletions src/parser/Sentence.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class Sentence {
kShowStats,
kShowTSClients,
kShowFTIndexes,
kDescribeUser,
kDeleteVertices,
kDeleteTags,
kDeleteEdges,
Expand Down
12 changes: 11 additions & 1 deletion src/parser/parser.yy
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ static constexpr size_t kCommentLengthLimit = 256;
%type <sentence> add_listener_sentence remove_listener_sentence list_listener_sentence

%type <sentence> admin_job_sentence
%type <sentence> create_user_sentence alter_user_sentence drop_user_sentence change_password_sentence
%type <sentence> create_user_sentence alter_user_sentence drop_user_sentence change_password_sentence describe_user_sentence
%type <sentence> show_queries_sentence kill_query_sentence
%type <sentence> show_sentence

Expand Down Expand Up @@ -2436,6 +2436,15 @@ column_property
}
;

describe_user_sentence
: KW_DESCRIBE KW_USER name_label {
$$ = new DescribeUserSentence($3);
}
| KW_DESC KW_USER name_label {
$$ = new DescribeUserSentence($3);
}
;

describe_tag_sentence
: KW_DESCRIBE KW_TAG name_label {
$$ = new DescribeTagSentence($3);
Expand Down Expand Up @@ -2685,6 +2694,7 @@ traverse_sentence
| delete_edge_sentence { $$ = $1; }
| show_queries_sentence { $$ = $1; }
| kill_query_sentence { $$ = $1; }
| describe_user_sentence { $$ = $1; }
;

piped_sentence
Expand Down
6 changes: 6 additions & 0 deletions tests/tck/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,12 @@ def executing_query(query, graph_spaces, session, request):
ngql = combine_query(query)
exec_query(request, ngql, session, graph_spaces)

@when(parse("executing query with user {username} with password {password}:\n{query}"))
def executing_query(username, password, conn_pool_to_first_graph_service, query, graph_spaces, request):
sess = conn_pool_to_first_graph_service.get_session(username, password)
ngql = combine_query(query)
exec_query(request, ngql, sess, graph_spaces)
sess.release()

@when(parse("profiling query:\n{query}"))
def profiling_query(query, graph_spaces, session, request):
Expand Down
Loading

0 comments on commit a14d7b4

Please sign in to comment.