diff --git a/ydb/core/security/ticket_parser_impl.h b/ydb/core/security/ticket_parser_impl.h index f93522d2c166..42c67684ace1 100644 --- a/ydb/core/security/ticket_parser_impl.h +++ b/ydb/core/security/ticket_parser_impl.h @@ -386,25 +386,8 @@ class TTicketParserImpl : public TActorBootstrapped { resourcePath->set_type(type); } - template <> - static void AddResourcePath(nebius::iam::v1::AuthorizeCheck* pathsContainer, const TString& id, const TString& type) { - auto resourcePath = pathsContainer->mutable_resource_path()->add_path(); - resourcePath->set_id(id); - Y_UNUSED(type); - } - - template - static void AddContainerId(TPathsContainerPtr pathsContainer, const TString& id) { - Y_UNUSED(pathsContainer, id); - } - - template <> - static void AddContainerId(nebius::iam::v1::AuthorizeCheck* pathsContainer, const TString& id) { - pathsContainer->set_container_id(id); - } - template - void addResourcePaths(const TTokenRecord& record, const TString& permission, TPathsContainerPtr pathsContainer) const { + void AddResourcePaths(const TTokenRecord& record, const TString& permission, TPathsContainerPtr pathsContainer) const { if (const auto databaseId = record.GetAttributeValue(permission, "database_id"); databaseId) { AddResourcePath(pathsContainer, databaseId, "ydb.database"); } else if (const auto serviceAccountId = record.GetAttributeValue(permission, "service_account_id"); serviceAccountId) { @@ -422,9 +405,28 @@ class TTicketParserImpl : public TActorBootstrapped { if (const TString gizmoId = record.GetAttributeValue(permission, "gizmo_id"); gizmoId) { AddResourcePath(pathsContainer, gizmoId, "iam.gizmo"); } + } - if (const TString containerId = record.GetAttributeValue(permission, "container_id"); containerId) { - AddContainerId(pathsContainer, containerId); + static void AddNebiusResourcePath(nebius::iam::v1::AuthorizeCheck* pathsContainer, const TString& id) { + pathsContainer->mutable_resource_path()->add_path()->set_id(id); + } + + static void AddNebiusContainerId(nebius::iam::v1::AuthorizeCheck* pathsContainer, const TString& id) { + pathsContainer->set_container_id(id); + } + + template + void AddNebiusResourcePaths(const TTokenRecord& record, const TString& permission, nebius::iam::v1::AuthorizeCheck* pathsContainer) const { + // Use attribute "database_id" as our resource id + // IAM can link roles for resource + if (const auto databaseId = record.GetAttributeValue(permission, "database_id"); databaseId) { + AddNebiusResourcePath(pathsContainer, databaseId); + } + + // Use attribute "folder_id" as container id that contains our database + // IAM can link roles for containers hierarchy + if (const auto folderId = record.GetAttributeValue(permission, "folder_id"); folderId) { + AddNebiusContainerId(pathsContainer, folderId); } } @@ -435,7 +437,7 @@ class TTicketParserImpl : public TActorBootstrapped { auto request = CreateAccessServiceRequest(key, record); request->Request.set_permission(permissionName); - addResourcePaths(record, permissionName, &request->Request); + AddResourcePaths(record, permissionName, &request->Request); record.ResponsesLeft++; Send(AccessServiceValidatorV1, request.Release()); } @@ -447,7 +449,7 @@ class TTicketParserImpl : public TActorBootstrapped { TStringBuilder requestForPermissions; for (const auto& [permissionName, permissionRecord] : record.Permissions) { auto action = request->Request.mutable_actions()->add_items(); - addResourcePaths(record, permissionName, action); + AddResourcePaths(record, permissionName, action); action->set_permission(permissionName); requestForPermissions << " " << permissionName; } @@ -466,7 +468,7 @@ class TTicketParserImpl : public TActorBootstrapped { auto& check = (*request->Request.mutable_checks())[i]; check.set_iam_token(record.Ticket); check.mutable_permission()->set_name(permissionName); - addResourcePaths(record, permissionName, &check); + AddNebiusResourcePaths(record, permissionName, &check); requestForPermissions << " " << permissionName; ++i; } @@ -1082,6 +1084,9 @@ class TTicketParserImpl : public TActorBootstrapped { if (permissionRecord.IsRequired()) { hasRequiredPermissionFailed = true; errorMessage << permissionIt->first << " for"; + if (check.container_id()) { + errorMessage << ' ' << check.container_id(); + } for (const auto& resourcePath : check.resource_path().path()) { errorMessage << ' ' << resourcePath.id(); } diff --git a/ydb/core/security/ticket_parser_ut.cpp b/ydb/core/security/ticket_parser_ut.cpp index 98318fb497c5..42fda3cc0da8 100644 --- a/ydb/core/security/ticket_parser_ut.cpp +++ b/ydb/core/security/ticket_parser_ut.cpp @@ -1668,8 +1668,7 @@ Y_UNIT_TEST_SUITE(TTicketParserTest) { TVector> attrs = {{"folder_id", "aaaa1234"}, {"database_id", "bbbb4554"}}; if constexpr (IsNebiusAccessService()) { - accessServiceMock.ContainerId = "my_container"; - attrs.emplace_back("container_id", "my_container"); + accessServiceMock.ContainerId = "aaaa1234"; } // Authorization successful. @@ -1771,7 +1770,10 @@ Y_UNIT_TEST_SUITE(TTicketParserTest) { UNIT_ASSERT(!result->Error.Retryable); UNIT_ASSERT_VALUES_EQUAL(result->Error.Message, "Access Denied"); - // Authorization successful with right folder_id. + if constexpr (IsNebiusAccessService()) { + accessServiceMock.ContainerId = "aaaa1234"; + } + accessServiceMock.AllowedResourceIds.clear(); accessServiceMock.AllowedResourceIds.emplace("aaaa1234"); runtime->Send(new IEventHandle(MakeTicketParserID(), sender, new TEvTicketParser::TEvAuthorizeTicket( userToken, @@ -1781,8 +1783,13 @@ Y_UNIT_TEST_SUITE(TTicketParserTest) { UNIT_ASSERT_C(result->Error.empty(), result->Error); UNIT_ASSERT_C(result->Token->IsExist("something.read-XXXXXXXX@as"), result->Token->ShortDebugString()); + if constexpr (IsNebiusAccessService()) { + accessServiceMock.ContainerId = ""; + } else { + accessServiceMock.AllowedResourceIds.clear(); + } + // Authorization successful with right database_id. - accessServiceMock.AllowedResourceIds.clear(); accessServiceMock.AllowedResourceIds.emplace("bbbb4554"); runtime->Send(new IEventHandle(MakeTicketParserID(), sender, new TEvTicketParser::TEvAuthorizeTicket( userToken, @@ -1792,17 +1799,19 @@ Y_UNIT_TEST_SUITE(TTicketParserTest) { UNIT_ASSERT_C(result->Error.empty(), result->Error); UNIT_ASSERT_C(result->Token->IsExist("something.read-bbbb4554@as"), result->Token->ShortDebugString()); - // Authorization successful for gizmo resource - accessServiceMock.AllowedResourceIds.clear(); - accessServiceMock.AllowedResourceIds.emplace("gizmo"); - runtime->Send(new IEventHandle(MakeTicketParserID(), sender, new TEvTicketParser::TEvAuthorizeTicket( - userToken, - {{"gizmo_id", "gizmo"}, }, - {"monitoring.view"})), 0); - result = runtime->GrabEdgeEvent(handle); - UNIT_ASSERT_C(result->Error.empty(), result->Error); - UNIT_ASSERT_C(result->Token->IsExist("monitoring.view@as"), result->Token->ShortDebugString()); - UNIT_ASSERT_C(result->Token->IsExist("monitoring.view-gizmo@as"), result->Token->ShortDebugString()); + if constexpr (!IsNebiusAccessService()) { + // Authorization successful for gizmo resource + accessServiceMock.AllowedResourceIds.clear(); + accessServiceMock.AllowedResourceIds.emplace("gizmo"); + runtime->Send(new IEventHandle(MakeTicketParserID(), sender, new TEvTicketParser::TEvAuthorizeTicket( + userToken, + {{"gizmo_id", "gizmo"}, }, + {"monitoring.view"})), 0); + result = runtime->GrabEdgeEvent(handle); + UNIT_ASSERT_C(result->Error.empty(), result->Error); + UNIT_ASSERT_C(result->Token->IsExist("monitoring.view@as"), result->Token->ShortDebugString()); + UNIT_ASSERT_C(result->Token->IsExist("monitoring.view-gizmo@as"), result->Token->ShortDebugString()); + } } Y_UNIT_TEST(Authorization) { @@ -1848,6 +1857,9 @@ Y_UNIT_TEST_SUITE(TTicketParserTest) { // Access Server Mock TAccessServiceMock accessServiceMock; + if constexpr (IsNebiusAccessService()) { + accessServiceMock.ContainerId = "aaaa1234"; + } grpc::ServerBuilder builder; builder.AddListeningPort(accessServiceEndpoint, grpc::InsecureServerCredentials()).RegisterService(&accessServiceMock); std::unique_ptr accessServer(builder.BuildAndStart()); diff --git a/ydb/library/testlib/service_mocks/nebius_access_service_mock.h b/ydb/library/testlib/service_mocks/nebius_access_service_mock.h index 8bbb2c8a2a52..59c9bfd1965a 100644 --- a/ydb/library/testlib/service_mocks/nebius_access_service_mock.h +++ b/ydb/library/testlib/service_mocks/nebius_access_service_mock.h @@ -212,6 +212,9 @@ class TTicketParserNebiusAccessServiceMock : public nebius::iam::v1::AccessServi bool allowedResource = true; if (!AllowedResourceIds.empty()) { allowedResource = false; + if (IsIn(AllowedResourceIds, check.container_id())) { + allowedResource = true; + } for (const auto& resourcePath : check.resource_path().path()) { if (IsIn(AllowedResourceIds, resourcePath.id())) { allowedResource = true;