diff options
author | hcpp <hcpp@yandex-team.ru> | 2022-04-25 11:20:43 +0300 |
---|---|---|
committer | hcpp <hcpp@yandex-team.ru> | 2022-04-25 11:20:43 +0300 |
commit | 0ecf27e611841e6dfdadc80e67f80be091e0ccc7 (patch) | |
tree | f140fb86514195335914d9678b2c4b76bad10ba5 | |
parent | 26a47007a80a1805a801dafff0c03dc13b88df3f (diff) | |
download | ydb-0ecf27e611841e6dfdadc80e67f80be091e0ccc7.tar.gz |
PR from branch users/hcpp/required_permissions YQ-973
base template
auth error has been added
ref:412889637a6da80069cd596f1308061d73087cf4
-rw-r--r-- | ydb/core/base/ticket_parser.h | 51 | ||||
-rw-r--r-- | ydb/core/grpc_services/base/base.h | 15 | ||||
-rw-r--r-- | ydb/core/grpc_services/grpc_request_check_actor.h | 1 | ||||
-rw-r--r-- | ydb/core/grpc_services/service_yq.h | 20 | ||||
-rw-r--r-- | ydb/core/security/ticket_parser.cpp | 2 | ||||
-rw-r--r-- | ydb/services/yq/grpc_service.cpp | 300 |
6 files changed, 266 insertions, 123 deletions
diff --git a/ydb/core/base/ticket_parser.h b/ydb/core/base/ticket_parser.h index 5ebde54b6cb..d1b8454e6b9 100644 --- a/ydb/core/base/ticket_parser.h +++ b/ydb/core/base/ticket_parser.h @@ -25,9 +25,45 @@ namespace NKikimr { static_assert(EvEnd < EventSpaceEnd(TKikimrEvents::ES_TICKET_PARSER), "expect EvEnd < EventSpaceEnd(TKikimrEvents::ES_TICKET_PARSER)"); struct TEvAuthorizeTicket : TEventLocal<TEvAuthorizeTicket, EvAuthorizeTicket> { + struct TPermission { + TString Permission; + bool Required = false; + }; + + static TPermission Required(const TString& permission) { + return { + .Permission = permission, + .Required = true + }; + } + + static TPermission Optional(const TString& permission) { + return { + .Permission = permission, + .Required = false + }; + } + + static TVector<TPermission> ToPermissions(const TVector<TString>& permissions) { + TVector<TPermission> result; + std::transform(permissions.begin(), permissions.end(), std::back_inserter(result), + [](const TString& s) { return Optional(s); }); + return result; + } + struct TEntry { - TStackVec<TString> Permissions; + TStackVec<TPermission> Permissions; TStackVec<std::pair<TString, TString>> Attributes; + + TEntry(const TVector<TString>& permissions, const TVector<std::pair<TString, TString>>& attributes) + : Permissions(ToPermissions(permissions)) + , Attributes(attributes) + {} + + TEntry(const TVector<TPermission>& permissions, const TVector<std::pair<TString, TString>>& attributes) + : Permissions(permissions) + , Attributes(attributes) + {} }; const TString Database; @@ -76,12 +112,23 @@ namespace NKikimr { TEvAuthorizeTicket(const TString& ticket, const TVector<std::pair<TString, TString>>& attributes, const TVector<TString>& permissions) : Ticket(ticket) - , Entries({{permissions, attributes}}) + , Entries({{ToPermissions(permissions), attributes}}) {} TEvAuthorizeTicket(const TString& ticket, const TString& peerName, const TVector<std::pair<TString, TString>>& attributes, const TVector<TString>& permissions) : Ticket(ticket) , PeerName(peerName) + , Entries({{ToPermissions(permissions), attributes}}) + {} + + TEvAuthorizeTicket(const TString& ticket, const TVector<std::pair<TString, TString>>& attributes, const TVector<TPermission>& permissions) + : Ticket(ticket) + , Entries({{permissions, attributes}}) + {} + + TEvAuthorizeTicket(const TString& ticket, const TString& peerName, const TVector<std::pair<TString, TString>>& attributes, const TVector<TPermission>& permissions) + : Ticket(ticket) + , PeerName(peerName) , Entries({{permissions, attributes}}) {} diff --git a/ydb/core/grpc_services/base/base.h b/ydb/core/grpc_services/base/base.h index 5b8c53c5ec9..4aa27a5ba4e 100644 --- a/ydb/core/grpc_services/base/base.h +++ b/ydb/core/grpc_services/base/base.h @@ -611,8 +611,12 @@ public: } void ReplyUnauthenticated(const TString& in) override { - const TString message = in.empty() ? TString("unauthenticated") : TString("unauthenticated, ") + in; - Ctx_->Finish(grpc::Status(grpc::StatusCode::UNAUTHENTICATED, message)); + TStringBuilder builder; + builder << (in.empty() ? TString("unauthenticated") : TString("unauthenticated, ")) << in; + for (const auto& issue: IssueManager_.GetIssues()) { + builder << " " << issue.Message; + } + Ctx_->Finish(grpc::Status(grpc::StatusCode::UNAUTHENTICATED, builder)); } void ReplyUnavaliable() override { @@ -867,7 +871,12 @@ public: } void ReplyUnauthenticated(const TString& in) override { - Ctx_->ReplyUnauthenticated(in); + TStringBuilder builder; + builder << in; + for (const auto& issue: IssueManager.GetIssues()) { + builder << " " << issue.Message; + } + Ctx_->ReplyUnauthenticated(builder); } void SetInternalToken(const TString& token) override { diff --git a/ydb/core/grpc_services/grpc_request_check_actor.h b/ydb/core/grpc_services/grpc_request_check_actor.h index 52342d0108a..869e3ea23e4 100644 --- a/ydb/core/grpc_services/grpc_request_check_actor.h +++ b/ydb/core/grpc_services/grpc_request_check_actor.h @@ -34,6 +34,7 @@ public: } else { GrpcRequestBaseCtx_->UpdateAuthState(NGrpc::TAuthState::AS_FAIL); } + GrpcRequestBaseCtx_->RaiseIssue(NYql::TIssue{error.Message}); ReplyBackAndDie(); } diff --git a/ydb/core/grpc_services/service_yq.h b/ydb/core/grpc_services/service_yq.h index 85b5a3ced80..9453dd4b7dd 100644 --- a/ydb/core/grpc_services/service_yq.h +++ b/ydb/core/grpc_services/service_yq.h @@ -14,42 +14,42 @@ class IFacilityProvider; template <typename TReq, typename TResp> class TGrpcYqRequestOperationCall : public TGrpcRequestOperationCall<TReq, TResp> { - public: using TBase = TGrpcRequestOperationCall<TReq, TResp>; using TBase::GetProtoRequest; using TBase::GetPeerMetaValues; + using NPerms = NKikimr::TEvTicketParser::TEvAuthorizeTicket; - const TVector<TString>& Permissions; + const std::function<TVector<NPerms::TPermission>(const TReq&)>& Permissions; TVector<TString> Sids; TGrpcYqRequestOperationCall(NGrpc::IRequestContextBase* ctx, - void (*cb)(std::unique_ptr<IRequestOpCtx>, const IFacilityProvider&), - const TVector<TString>& permissions) + void (*cb)(std::unique_ptr<IRequestOpCtx>, const IFacilityProvider&), + const std::function<TVector<NPerms::TPermission>(const TReq&)>& permissions) : TGrpcRequestOperationCall<TReq, TResp>(ctx, cb, {}), Permissions(permissions) { } bool TryCustomAttributeProcess(const TSchemeBoardEvents::TDescribeSchemeResult& , ICheckerIface* iface) override { - const TString scope = GetPeerMetaValues("x-yq-scope").GetOrElse(""); if (scope.StartsWith("yandexcloud://")) { const TVector<TString> path = StringSplitter(scope).Split('/').SkipEmpty(); if (path.size() == 2 || path.size() == 3) { const TString& folderId = path.back(); + const auto& permissions = Permissions(*GetProtoRequest()); TVector<TEvTicketParser::TEvAuthorizeTicket::TEntry> entries {{ - Permissions, + permissions, { {"folder_id", folderId}, {"database_id", "db"} } }}; - std::transform(Permissions.begin(), Permissions.end(), std::back_inserter(Sids), - [](const TString& s) -> TString { return s + "@as"; }); + std::transform(permissions.begin(), permissions.end(), std::back_inserter(Sids), + [](const auto& s) -> TString { return s.Permission + "@as"; }); auto serviceAccountId = NYq::ExtractServiceAccountId(*GetProtoRequest()); if (serviceAccountId) { entries.push_back({ - {"iam.serviceAccounts.use"}, + {{NPerms::Required("iam.serviceAccounts.use")}}, { {"service_account_id", serviceAccountId}, {"database_id", "db"} @@ -61,7 +61,7 @@ public: return true; } } - + return false; } }; diff --git a/ydb/core/security/ticket_parser.cpp b/ydb/core/security/ticket_parser.cpp index c7d024d03dc..5654a8310b7 100644 --- a/ydb/core/security/ticket_parser.cpp +++ b/ydb/core/security/ticket_parser.cpp @@ -136,7 +136,7 @@ class TTicketParser : public TActorBootstrapped<TTicketParser> { if (it != entry.Permissions.begin()) { key << '-'; } - key << *it; + key << it->Permission << "(" << it->Required << ")"; } } return key.Str(); diff --git a/ydb/services/yq/grpc_service.cpp b/ydb/services/yq/grpc_service.cpp index bb71dde0926..69a20ecccd3 100644 --- a/ydb/services/yq/grpc_service.cpp +++ b/ydb/services/yq/grpc_service.cpp @@ -35,113 +35,199 @@ void TGRpcYandexQueryService::DecRequest() { void TGRpcYandexQueryService::SetupIncomingRequests(NGrpc::TLoggerPtr logger) { auto getCounterBlock = CreateCounterCb(Counters_, ActorSystem_); - static const TVector<TString> CreateQueryPermissions = { - "yq.queries.create", - "yq.queries.invoke", - "yq.connections.use", - "yq.bindings.use", - "yq.resources.managePublic" - }; - static const TVector<TString> ListQueriesPermissions = { - "yq.queries.get", - "yq.resources.viewPublic", - "yq.resources.viewPrivate" - }; - static const TVector<TString> DescribeQueryPermissions = { - "yq.queries.get", - "yq.queries.viewAst", - "yq.resources.viewPublic", - "yq.resources.viewPrivate" - }; - static const TVector<TString> GetQueryStatusPermissions = { - "yq.queries.getStatus", - "yq.resources.viewPublic", - "yq.resources.viewPrivate" - }; - static const TVector<TString> ModifyQueryPermissions = { - "yq.queries.update", - "yq.queries.invoke", - "yq.connections.use", - "yq.bindings.use", - "yq.resources.managePublic", - "yq.resources.managePrivate" - }; - static const TVector<TString> DeleteQueryPermissions = { - "yq.queries.delete", - "yq.resources.managePublic", - "yq.resources.managePrivate" - }; - static const TVector<TString> ControlQueryPermissions = { - "yq.queries.control", - "yq.resources.managePublic", - "yq.resources.managePrivate" - }; - static const TVector<TString> GetResultDataPermissions = { - "yq.queries.getData", - "yq.resources.viewPublic", - "yq.resources.viewPrivate" - }; - static const TVector<TString> ListJobsPermissions = { - "yq.jobs.get", - "yq.resources.viewPublic", - "yq.resources.viewPrivate" - }; - static const TVector<TString> DescribeJobPermissions = { - "yq.jobs.get", - "yq.resources.viewPublic", - "yq.resources.viewPrivate" - }; - static const TVector<TString> CreateConnectionPermissions = { - "yq.connections.create", - "yq.resources.managePublic", - }; - static const TVector<TString> ListConnectionsPermissions = { - "yq.connections.get", - "yq.resources.viewPublic", - "yq.resources.viewPrivate" - }; - static const TVector<TString> DescribeConnectionPermissions = { - "yq.connections.get", - "yq.resources.viewPublic", - "yq.resources.viewPrivate" - }; - static const TVector<TString> ModifyConnectionPermissions = { - "yq.connections.update", - "yq.resources.managePublic", - "yq.resources.managePrivate", - }; - static const TVector<TString> DeleteConnectionPermissions = { - "yq.connections.delete", - "yq.resources.managePublic", - "yq.resources.managePrivate" - }; - static const TVector<TString> TestConnectionPermissions = { - "yq.connections.create", - }; - static const TVector<TString> CreateBindingPermissions = { - "yq.bindings.create", - "yq.resources.managePublic" - }; - static const TVector<TString> ListBindingsPermissions = { - "yq.bindings.get", - "yq.resources.viewPublic", - "yq.resources.viewPrivate" - }; - static const TVector<TString> DescribeBindingPermissions = { - "yq.bindings.get", - "yq.resources.viewPublic", - "yq.resources.viewPrivate" - }; - static const TVector<TString> ModifyBindingPermissions = { - "yq.bindings.update", - "yq.resources.managePublic", - "yq.resources.managePrivate" - }; - static const TVector<TString> DeleteBindingPermissions = { - "yq.bindings.delete", - "yq.resources.managePublic", - "yq.resources.managePrivate" - }; + using NPerms = NKikimr::TEvTicketParser::TEvAuthorizeTicket; + + static const std::function CreateQueryPermissions{[](const YandexQuery::CreateQueryRequest& request) { + TVector<NPerms::TPermission> permissions{ + NPerms::Required("yq.queries.create"), + NPerms::Optional("yq.connections.use"), + NPerms::Optional("yq.bindings.use") + }; + if (request.execute_mode() != YandexQuery::SAVE) { + permissions.push_back(NPerms::Required("yq.queries.invoke")); + } + if (request.content().acl().visibility() == YandexQuery::Acl::SCOPE) { + permissions.push_back(NPerms::Required("yq.resources.managePublic")); + } + return permissions; + }}; + + static const std::function ListQueriesPermissions{[](const YandexQuery::ListQueriesRequest&) -> TVector<NPerms::TPermission> { + return { + NPerms::Required("yq.queries.get"), + NPerms::Optional("yq.resources.viewPublic"), + NPerms::Optional("yq.resources.viewPrivate") + }; + }}; + + static const std::function DescribeQueryPermissions{[](const YandexQuery::DescribeQueryRequest&) -> TVector<NPerms::TPermission> { + return { + NPerms::Required("yq.queries.get"), + NPerms::Optional("yq.queries.viewAst"), + NPerms::Optional("yq.resources.viewPublic"), + NPerms::Optional("yq.resources.viewPrivate") + }; + }}; + + static const std::function GetQueryStatusPermissions{[](const YandexQuery::GetQueryStatusRequest&) -> TVector<NPerms::TPermission> { + return { + NPerms::Required("yq.queries.getStatus"), + NPerms::Optional("yq.resources.viewPublic"), + NPerms::Optional("yq.resources.viewPrivate") + }; + }}; + + static const std::function ModifyQueryPermissions{[](const YandexQuery::ModifyQueryRequest& request) { + TVector<NPerms::TPermission> permissions{ + NPerms::Required("yq.queries.update"), + NPerms::Optional("yq.connections.use"), + NPerms::Optional("yq.bindings.use"), + NPerms::Optional("yq.resources.managePrivate") + }; + if (request.execute_mode() != YandexQuery::SAVE) { + permissions.push_back(NPerms::Required("yq.queries.invoke")); + } + if (request.content().acl().visibility() == YandexQuery::Acl::SCOPE) { + permissions.push_back(NPerms::Required("yq.resources.managePublic")); + } + return permissions; + }}; + + static const std::function DeleteQueryPermissions{[](const YandexQuery::DeleteQueryRequest&) -> TVector<NPerms::TPermission> { + return { + NPerms::Required("yq.queries.delete"), + NPerms::Optional("yq.resources.managePublic"), + NPerms::Optional("yq.resources.managePrivate") + }; + }}; + + static const std::function ControlQueryPermissions{[](const YandexQuery::ControlQueryRequest&) -> TVector<NPerms::TPermission> { + return { + NPerms::Required("yq.queries.control"), + NPerms::Optional("yq.resources.managePublic"), + NPerms::Optional("yq.resources.managePrivate") + }; + }}; + + static const std::function GetResultDataPermissions{[](const YandexQuery::GetResultDataRequest&) -> TVector<NPerms::TPermission> { + return { + NPerms::Required("yq.queries.getData"), + NPerms::Optional("yq.resources.viewPublic"), + NPerms::Optional("yq.resources.viewPrivate") + }; + }}; + + static const std::function ListJobsPermissions{[](const YandexQuery::ListJobsRequest&) -> TVector<NPerms::TPermission> { + return { + NPerms::Required("yq.jobs.get"), + NPerms::Optional("yq.resources.viewPublic"), + NPerms::Optional("yq.resources.viewPrivate") + }; + }}; + + static const std::function DescribeJobPermissions{[](const YandexQuery::DescribeJobRequest&) -> TVector<NPerms::TPermission> { + return { + NPerms::Required("yq.jobs.get"), + NPerms::Optional("yq.resources.viewPublic"), + NPerms::Optional("yq.resources.viewPrivate") + }; + }}; + + static const std::function CreateConnectionPermissions{[](const YandexQuery::CreateConnectionRequest& request) { + TVector<NPerms::TPermission> permissions{ + NPerms::Required("yq.connections.create"), + }; + if (request.content().acl().visibility() == YandexQuery::Acl::SCOPE) { + permissions.push_back(NPerms::Required("yq.resources.managePublic")); + } + return permissions; + }}; + + static const std::function ListConnectionsPermissions{[](const YandexQuery::ListConnectionsRequest&) -> TVector<NPerms::TPermission> { + return { + NPerms::Required("yq.connections.get"), + NPerms::Optional("yq.resources.viewPublic"), + NPerms::Optional("yq.resources.viewPrivate") + }; + }}; + + static const std::function DescribeConnectionPermissions{[](const YandexQuery::DescribeConnectionRequest&) -> TVector<NPerms::TPermission> { + return { + NPerms::Required("yq.connections.get"), + NPerms::Optional("yq.resources.viewPublic"), + NPerms::Optional("yq.resources.viewPrivate") + }; + }}; + + static const std::function ModifyConnectionPermissions{[](const YandexQuery::ModifyConnectionRequest& request) { + TVector<NPerms::TPermission> permissions{ + NPerms::Required("yq.connections.update"), + NPerms::Optional("yq.resources.managePrivate") + }; + if (request.content().acl().visibility() == YandexQuery::Acl::SCOPE) { + permissions.push_back(NPerms::Required("yq.resources.managePublic")); + } + return permissions; + }}; + + static const std::function DeleteConnectionPermissions{[](const YandexQuery::DeleteConnectionRequest&) -> TVector<NPerms::TPermission> { + return { + NPerms::Required("yq.connections.delete"), + NPerms::Optional("yq.resources.managePublic"), + NPerms::Optional("yq.resources.managePrivate") + }; + }}; + + static const std::function TestConnectionPermissions{[](const YandexQuery::TestConnectionRequest&) -> TVector<NPerms::TPermission> { + return { + NPerms::Required("yq.connections.create") + }; + }}; + + static const std::function CreateBindingPermissions{[](const YandexQuery::CreateBindingRequest& request) { + TVector<NPerms::TPermission> permissions{ + NPerms::Required("yq.bindings.create"), + }; + if (request.content().acl().visibility() == YandexQuery::Acl::SCOPE) { + permissions.push_back(NPerms::Required("yq.resources.managePublic")); + } + return permissions; + }}; + + static const std::function ListBindingsPermissions{[](const YandexQuery::ListBindingsRequest&) -> TVector<NPerms::TPermission> { + return { + NPerms::Required("yq.bindings.get"), + NPerms::Optional("yq.resources.viewPublic"), + NPerms::Optional("yq.resources.viewPrivate") + }; + }}; + + static const std::function DescribeBindingPermissions{[](const YandexQuery::DescribeBindingRequest&) -> TVector<NPerms::TPermission> { + return { + NPerms::Required("yq.bindings.get"), + NPerms::Optional("yq.resources.viewPublic"), + NPerms::Optional("yq.resources.viewPrivate") + }; + }}; + + static const std::function ModifyBindingPermissions{[](const YandexQuery::ModifyBindingRequest& request) { + TVector<NPerms::TPermission> permissions{ + NPerms::Required("yq.bindings.update"), + NPerms::Optional("yq.resources.managePrivate") + }; + if (request.content().acl().visibility() == YandexQuery::Acl::SCOPE) { + permissions.push_back(NPerms::Required("yq.resources.managePublic")); + } + return permissions; + }}; + + static const std::function DeleteBindingPermissions{[](const YandexQuery::DeleteBindingRequest&) -> TVector<NPerms::TPermission> { + return { + NPerms::Required("yq.bindings.delete"), + NPerms::Optional("yq.resources.managePublic"), + NPerms::Optional("yq.resources.managePrivate") + }; + }}; #ifdef ADD_REQUEST #error ADD_REQUEST macro already defined |