Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

describe the user #3300

Merged
merged 23 commits into from
Nov 25, 2021
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -386,6 +387,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 @@ -183,6 +183,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
20 changes: 20 additions & 0 deletions src/graph/service/PermissionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,26 @@ Status PermissionManager::canWriteUser(ClientSession *session) {
}
}

// static
Status PermissionManager::canReadUser(ClientSession *session, const std::string &targetUser) {
if (!FLAGS_enable_authorize) {
return Status::OK();
}
// Cloud auth user cannot create user
heroicNeZha marked this conversation as resolved.
Show resolved Hide resolved
if (FLAGS_auth_type == "cloud") {
return Status::PermissionError("Cloud authenticate user can't write user.");
heroicNeZha marked this conversation as resolved.
Show resolved Hide resolved
}
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) {
heroicNeZha marked this conversation as resolved.
Show resolved Hide resolved
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 @@ -362,7 +362,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 @@ -2433,6 +2433,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 @@ -2714,6 +2723,7 @@ traverse_sentence
| delete_edge_sentence { $$ = $1; }
| show_queries_sentence { $$ = $1; }
| kill_query_sentence { $$ = $1; }
| describe_user_sentence { $$ = $1; }
Copy link
Contributor

@Shylock-Hg Shylock-Hg Nov 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The traverse_sentence means supporting input/output. Don't put it here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The desc_user_sentcence supports output pipe.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why need this? Normally, admin sentence don't support it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To Support desc user user1 | YIELD $-.role where $-.space == "space3"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this pass in discussion meeting?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yixinglu From Yee‘s conversation

;

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