From 9ffc50105c01aef1f027fdff825e5a14b9a3553f Mon Sep 17 00:00:00 2001 From: andrew stalin Date: Mon, 3 Feb 2025 11:23:32 +0700 Subject: [PATCH] Use the root domain as a database for all operations with users and groups (#13969) --- .../executer_actor/kqp_scheme_executer.cpp | 20 +++ .../tenants/test_users_groups_with_acl.py | 132 ++++++++++++++++++ ydb/tests/functional/tenants/ya.make | 1 + 3 files changed, 153 insertions(+) create mode 100644 ydb/tests/functional/tenants/test_users_groups_with_acl.py diff --git a/ydb/core/kqp/executer_actor/kqp_scheme_executer.cpp b/ydb/core/kqp/executer_actor/kqp_scheme_executer.cpp index f118fe0da405..3794f9a30df7 100644 --- a/ydb/core/kqp/executer_actor/kqp_scheme_executer.cpp +++ b/ydb/core/kqp/executer_actor/kqp_scheme_executer.cpp @@ -4,12 +4,15 @@ #include #include #include +#include #include +#include #include #include #include #include + namespace NKikimr::NKqp { using namespace NThreading; @@ -120,6 +123,15 @@ class TKqpSchemeExecuter : public TActorBootstrapped { Become(&TKqpSchemeExecuter::ExecuteState); } + TString GetDatabaseForLoginOperation() const { + const auto domainLoginOnly = AppData()->AuthConfig.GetDomainLoginOnly(); + const auto domain = AppData()->DomainsInfo ? AppData()->DomainsInfo->GetDomain() : nullptr; + const auto domainName = domain ? domain->Name : ""; + TString database; + return NSchemeHelpers::SetDatabaseForLoginOperation(database, domainLoginOnly, domainName, Database) + ? database : Database; + } + void MakeSchemeOperationRequest() { using TRequest = TEvTxUserProxy::TEvProposeTransaction; @@ -181,18 +193,21 @@ class TKqpSchemeExecuter : public TActorBootstrapped { case NKqpProto::TKqpSchemeOperation::kCreateUser: { const auto& modifyScheme = schemeOp.GetCreateUser(); ev->Record.MutableTransaction()->MutableModifyScheme()->CopyFrom(modifyScheme); + ev->Record.SetDatabaseName(GetDatabaseForLoginOperation()); break; } case NKqpProto::TKqpSchemeOperation::kAlterUser: { const auto& modifyScheme = schemeOp.GetAlterUser(); ev->Record.MutableTransaction()->MutableModifyScheme()->CopyFrom(modifyScheme); + ev->Record.SetDatabaseName(GetDatabaseForLoginOperation()); break; } case NKqpProto::TKqpSchemeOperation::kDropUser: { const auto& modifyScheme = schemeOp.GetDropUser(); ev->Record.MutableTransaction()->MutableModifyScheme()->CopyFrom(modifyScheme); + ev->Record.SetDatabaseName(GetDatabaseForLoginOperation()); break; } case NKqpProto::TKqpSchemeOperation::kCreateExternalTable: { @@ -214,30 +229,35 @@ class TKqpSchemeExecuter : public TActorBootstrapped { case NKqpProto::TKqpSchemeOperation::kCreateGroup: { const auto& modifyScheme = schemeOp.GetCreateGroup(); ev->Record.MutableTransaction()->MutableModifyScheme()->CopyFrom(modifyScheme); + ev->Record.SetDatabaseName(GetDatabaseForLoginOperation()); break; } case NKqpProto::TKqpSchemeOperation::kAddGroupMembership: { const auto& modifyScheme = schemeOp.GetAddGroupMembership(); ev->Record.MutableTransaction()->MutableModifyScheme()->CopyFrom(modifyScheme); + ev->Record.SetDatabaseName(GetDatabaseForLoginOperation()); break; } case NKqpProto::TKqpSchemeOperation::kRemoveGroupMembership: { const auto& modifyScheme = schemeOp.GetRemoveGroupMembership(); ev->Record.MutableTransaction()->MutableModifyScheme()->CopyFrom(modifyScheme); + ev->Record.SetDatabaseName(GetDatabaseForLoginOperation()); break; } case NKqpProto::TKqpSchemeOperation::kRenameGroup: { const auto& modifyScheme = schemeOp.GetRenameGroup(); ev->Record.MutableTransaction()->MutableModifyScheme()->CopyFrom(modifyScheme); + ev->Record.SetDatabaseName(GetDatabaseForLoginOperation()); break; } case NKqpProto::TKqpSchemeOperation::kDropGroup: { const auto& modifyScheme = schemeOp.GetDropGroup(); ev->Record.MutableTransaction()->MutableModifyScheme()->CopyFrom(modifyScheme); + ev->Record.SetDatabaseName(GetDatabaseForLoginOperation()); break; } diff --git a/ydb/tests/functional/tenants/test_users_groups_with_acl.py b/ydb/tests/functional/tenants/test_users_groups_with_acl.py new file mode 100644 index 000000000000..80be6eb38fa3 --- /dev/null +++ b/ydb/tests/functional/tenants/test_users_groups_with_acl.py @@ -0,0 +1,132 @@ +# -*- coding: utf-8 -*- + +import logging +import pytest +from ydb.tests.library.harness.kikimr_config import KikimrConfigGenerator +from ydb.tests.library.harness.ydb_fixtures import ydb_database_ctx +from ydb.tests.oss.ydb_sdk_import import ydb + + +logger = logging.getLogger(__name__) + + +DATABASE = '/Root/users/database' + + +@pytest.fixture(scope='module', params=[True, False], ids=['domain_login_only--true', 'domain_login_only--false']) +def domain_login_only(request): + return request.param + + +@pytest.fixture(scope='module') +def ydb_configurator(ydb_cluster_configuration, domain_login_only): + config_generator = KikimrConfigGenerator(**ydb_cluster_configuration) + config_generator.yaml_config['auth_config'] = { + 'domain_login_only': domain_login_only, + } + return config_generator + + +@pytest.fixture(scope='function') +def domain_admin_driver_config(ydb_endpoint): + return ydb.DriverConfig( + endpoint=ydb_endpoint, + database="/Root", + ) + + +@pytest.fixture(scope='function') +def tenant_admin_driver_config(ydb_endpoint): + return ydb.DriverConfig( + endpoint=ydb_endpoint, + database=DATABASE, + ) + + +@pytest.fixture(scope='function') +def tenant_user_driver_config(ydb_endpoint): + return ydb.DriverConfig( + endpoint=ydb_endpoint, + database=DATABASE, + credentials=ydb.StaticCredentials.from_user_password('user', ''), + ) + + +def yql_create_user(config): + with ydb.Driver(config) as driver: + driver.wait() + script_client = ydb.ScriptingClient(driver) + script_client.execute_yql('CREATE USER user;') + script_client.execute_yql('ALTER USER user WITH PASSWORD NULL;') + script_client.execute_yql('DROP USER user;') + + +def query_create_user(config): + with ydb.Driver(config) as driver: + with ydb.QuerySessionPool(driver, size=1) as pool: + pool.execute_with_retries('CREATE USER user;') + pool.execute_with_retries('ALTER USER user WITH PASSWORD NULL;') + pool.execute_with_retries('DROP USER user;') + + +def yql_create_group(config): + with ydb.Driver(config) as driver: + driver.wait() + script_client = ydb.ScriptingClient(driver) + script_client.execute_yql('CREATE GROUP group;') + script_client.execute_yql('CREATE USER user;') + script_client.execute_yql('ALTER GROUP group ADD USER user;') + script_client.execute_yql('ALTER GROUP group DROP USER user;') + script_client.execute_yql('DROP GROUP group;') + script_client.execute_yql('DROP USER user;') + + +def query_create_group(config): + with ydb.Driver(config) as driver: + with ydb.QuerySessionPool(driver, size=1) as pool: + pool.execute_with_retries('CREATE GROUP group;') + pool.execute_with_retries('CREATE USER user;') + pool.execute_with_retries('ALTER GROUP group ADD USER user;') + pool.execute_with_retries('ALTER GROUP group DROP USER user;') + pool.execute_with_retries('DROP GROUP group;') + pool.execute_with_retries('DROP USER user;') + + +def test_yql_create_user_by_domain_admin(ydb_cluster, domain_admin_driver_config): + with ydb_database_ctx(ydb_cluster, DATABASE): + yql_create_user(domain_admin_driver_config) + + +def test_yql_create_user_by_tenant_admin(ydb_cluster, tenant_admin_driver_config): + with ydb_database_ctx(ydb_cluster, DATABASE): + yql_create_user(tenant_admin_driver_config) + + +def test_yql_create_group_by_domain_admin(ydb_cluster, domain_admin_driver_config): + with ydb_database_ctx(ydb_cluster, DATABASE): + yql_create_group(domain_admin_driver_config) + + +def test_yql_create_group_by_tenant_admin(ydb_cluster, tenant_admin_driver_config): + with ydb_database_ctx(ydb_cluster, DATABASE): + yql_create_group(tenant_admin_driver_config) + + +def test_query_create_user_by_domain_admin(ydb_cluster, domain_admin_driver_config): + with ydb_database_ctx(ydb_cluster, DATABASE): + query_create_user(domain_admin_driver_config) + + +def test_query_create_user_by_tenant_admin(ydb_cluster, tenant_admin_driver_config): + with ydb_database_ctx(ydb_cluster, DATABASE): + query_create_user(tenant_admin_driver_config) + + +def test_query_create_group_by_domain_admin(ydb_cluster, domain_admin_driver_config): + with ydb_database_ctx(ydb_cluster, DATABASE): + query_create_group(domain_admin_driver_config) + + +def test_query_create_group_by_tenant_admin(ydb_cluster, tenant_admin_driver_config): + with ydb_database_ctx(ydb_cluster, DATABASE): + query_create_group(tenant_admin_driver_config) diff --git a/ydb/tests/functional/tenants/ya.make b/ydb/tests/functional/tenants/ya.make index f9e02d4d2f50..3f0c2acabf56 100644 --- a/ydb/tests/functional/tenants/ya.make +++ b/ydb/tests/functional/tenants/ya.make @@ -10,6 +10,7 @@ TEST_SRCS( test_storage_config.py test_system_views.py test_publish_into_schemeboard_with_common_ssring.py + test_users_groups_with_acl.py ) SPLIT_FACTOR(20)