diff options
author | Ilnaz Nizametdinov <i.nizametdinov@gmail.com> | 2022-07-04 20:10:43 +0300 |
---|---|---|
committer | Ilnaz Nizametdinov <i.nizametdinov@gmail.com> | 2022-07-04 20:10:43 +0300 |
commit | 16c46dc5e7e58898f4914b6c133e8d55d14ccd72 (patch) | |
tree | d555bcb6ddb4b9d3fb6167ab274f9b630c30f761 | |
parent | 9253fb8658089f014b3126076642e528d24d8145 (diff) | |
download | ydb-16c46dc5e7e58898f4914b6c133e8d55d14ccd72.tar.gz |
Verify that path belongs to the specified domain KIKIMR-14784
ref:473d2fb21cfa2b65d075cd61dbfd7ef7da233ac2
-rw-r--r-- | ydb/core/tx/scheme_board/cache.cpp | 93 | ||||
-rw-r--r-- | ydb/core/tx/scheme_board/cache_ut.cpp | 44 | ||||
-rw-r--r-- | ydb/core/tx/scheme_cache/scheme_cache.h | 2 | ||||
-rw-r--r-- | ydb/tests/functional/tenants/test_dynamic_tenants.py | 2 | ||||
-rw-r--r-- | ydb/tests/functional/tenants/test_tenants.py | 6 |
5 files changed, 112 insertions, 35 deletions
diff --git a/ydb/core/tx/scheme_board/cache.cpp b/ydb/core/tx/scheme_board/cache.cpp index da39c00ff0d..321e30b4ccf 100644 --- a/ydb/core/tx/scheme_board/cache.cpp +++ b/ydb/core/tx/scheme_board/cache.cpp @@ -161,7 +161,21 @@ namespace { } template <typename TContextPtr, typename TEvResult, typename TDerived> - class TAclChecker: public TActorBootstrapped<TDerived> { + class TAccessChecker: public TActorBootstrapped<TDerived> { + static bool IsDomain(TNavigate::TEntry& entry) { + switch (entry.Kind) { + case NSchemeCache::TSchemeCacheNavigate::KindSubdomain: + case NSchemeCache::TSchemeCacheNavigate::KindExtSubdomain: + return true; + default: + return false; + } + } + + static bool IsDomain(TResolve::TEntry&) { + return false; + } + static TIntrusivePtr<TSecurityObject> GetSecurityObject(const TNavigate::TEntry& entry) { return entry.SecurityObject; } @@ -235,61 +249,71 @@ namespace { } public: - explicit TAclChecker(TContextPtr context) + explicit TAccessChecker(TContextPtr context) : Context(context) { Y_VERIFY(!Context->WaitCounter); } void Bootstrap(const TActorContext&) { - if (Context->Request->UserToken == nullptr) { - SendResult(); - return; - } - for (auto& entry : Context->Request->ResultSet) { - auto securityObject = GetSecurityObject(entry); - if (securityObject == nullptr) { - continue; + if (!IsDomain(entry) && Context->ResolvedDomainInfo && entry.DomainInfo) { + // ^ It is allowed to describe subdomains by specifying root as DatabaseName + + if (Context->ResolvedDomainInfo->DomainKey != entry.DomainInfo->DomainKey) { + SBC_LOG_W("Path does not belong to the specified domain" + << ": self# " << this->SelfId() + << ", domain# " << Context->ResolvedDomainInfo->DomainKey + << ", path's domain# " << entry.DomainInfo->DomainKey); + + SetErrorAndClear(Context.Get(), entry); + } } + + if (Context->Request->UserToken) { + auto securityObject = GetSecurityObject(entry); + if (securityObject == nullptr) { + continue; + } - const ui32 access = GetAccess(entry); - if (!securityObject->CheckAccess(access, *Context->Request->UserToken)) { - SBC_LOG_W("Access denied" - << ": self# " << this->SelfId() - << ", for# " << Context->Request->UserToken->GetUserSID() - << ", access# " << NACLib::AccessRightsToString(access)); + const ui32 access = GetAccess(entry); + if (!securityObject->CheckAccess(access, *Context->Request->UserToken)) { + SBC_LOG_W("Access denied" + << ": self# " << this->SelfId() + << ", for# " << Context->Request->UserToken->GetUserSID() + << ", access# " << NACLib::AccessRightsToString(access)); - SetErrorAndClear(Context.Get(), entry); + SetErrorAndClear(Context.Get(), entry); + } } } SendResult(); } - using TBase = TAclChecker<TContextPtr, TEvResult, TDerived>; + using TBase = TAccessChecker<TContextPtr, TEvResult, TDerived>; private: TContextPtr Context; - }; // TAclChecker + }; // TAccessChecker - class TAclCheckerNavigate: public TAclChecker<TNavigateContextPtr, TEvNavigateResult, TAclCheckerNavigate> { + class TAccessCheckerNavigate: public TAccessChecker<TNavigateContextPtr, TEvNavigateResult, TAccessCheckerNavigate> { public: using TBase::TBase; }; - class TAclCheckerResolve: public TAclChecker<TResolveContextPtr, TEvResolveResult, TAclCheckerResolve> { + class TAccessCheckerResolve: public TAccessChecker<TResolveContextPtr, TEvResolveResult, TAccessCheckerResolve> { public: using TBase::TBase; }; - IActor* CreateAclChecker(TNavigateContextPtr context) { - return new TAclCheckerNavigate(context); + IActor* CreateAccessChecker(TNavigateContextPtr context) { + return new TAccessCheckerNavigate(context); } - IActor* CreateAclChecker(TResolveContextPtr context) { - return new TAclCheckerResolve(context); + IActor* CreateAccessChecker(TResolveContextPtr context) { + return new TAccessCheckerResolve(context); } class TWatchCache: public TMonitorableActor<TWatchCache> { @@ -2393,7 +2417,20 @@ class TSchemeCache: public TMonitorableActor<TSchemeCache> { template <typename TContextPtr> void Complete(TContextPtr context) { Counters.FinishRequest(Now() - context->CreatedAt); - Register(CreateAclChecker(context)); + Register(CreateAccessChecker(context)); + } + + template <typename TContext, typename TEvent> + TIntrusivePtr<TContext> MakeContext(TEvent& ev) const { + TIntrusivePtr<TContext> context(new TContext(ev->Sender, ev->Get()->Request, Now())); + + if (context->Request->DatabaseName) { + if (auto* db = Cache.FindPtr(CanonizePath(context->Request->DatabaseName))) { + context->ResolvedDomainInfo = db->GetDomainInfo(); + } + } + + return context; } void Handle(TEvTxProxySchemeCache::TEvNavigateKeySet::TPtr& ev) { @@ -2405,7 +2442,7 @@ class TSchemeCache: public TMonitorableActor<TSchemeCache> { return; } - TIntrusivePtr<TNavigateContext> context(new TNavigateContext(ev->Sender, ev->Get()->Request, Now())); + auto context = MakeContext<TNavigateContext>(ev); for (size_t i = 0; i < context->Request->ResultSet.size(); ++i) { auto& entry = context->Request->ResultSet[i]; @@ -2465,7 +2502,7 @@ class TSchemeCache: public TMonitorableActor<TSchemeCache> { return; } - TIntrusivePtr<TResolveContext> context(new TResolveContext(ev->Sender, ev->Get()->Request, Now())); + auto context = MakeContext<TResolveContext>(ev); auto pathExtractor = [](const TResolve::TEntry& entry) { const TKeyDesc* keyDesc = entry.KeyDescription.Get(); diff --git a/ydb/core/tx/scheme_board/cache_ut.cpp b/ydb/core/tx/scheme_board/cache_ut.cpp index c27b3517b34..8630e459817 100644 --- a/ydb/core/tx/scheme_board/cache_ut.cpp +++ b/ydb/core/tx/scheme_board/cache_ut.cpp @@ -57,6 +57,7 @@ public: UNIT_TEST(MigrationUndo); UNIT_TEST(MigrationDeletedPathNavigate); UNIT_TEST(WatchRoot); + UNIT_TEST(PathBelongsToDomain); UNIT_TEST_SUITE_END(); void Navigate(); @@ -76,6 +77,7 @@ public: void MigrationUndo(); void MigrationDeletedPathNavigate(); void WatchRoot(); + void PathBelongsToDomain(); protected: TNavigate::TEntry TestNavigateImpl(THolder<TNavigate> request, TNavigate::EStatus expectedStatus, @@ -948,6 +950,48 @@ void TCacheTest::WatchRoot() { SimulateSleep(*Context, TDuration::Seconds(1)); } +void TCacheTest::PathBelongsToDomain() { + ui64 txId = 100; + TestCreateSubDomain(*Context, ++txId, "/Root", "Name: \"SubDomain\""); + TestWaitNotification(*Context, {txId}, CreateNotificationSubscriber(*Context, TTestTxConfig::SchemeShard)); + TestMkDir(*Context, ++txId, "/Root/SubDomain", "DirA"); + + TTableId testId; + + // ok + { + auto request = MakeHolder<TNavigate>(); + request->DatabaseName = "/Root/SubDomain"; + auto& entry = request->ResultSet.emplace_back(); + entry.Path = SplitPath("/Root/SubDomain/DirA"); + entry.RequestType = TNavigate::TEntry::ERequestType::ByPath; + auto result = TestNavigateImpl(std::move(request), TNavigate::EStatus::Ok, + "", TNavigate::EOp::OpPath, false, true); + + testId = result.TableId; + } + // error, by path + { + auto request = MakeHolder<TNavigate>(); + request->DatabaseName = "/Root"; + auto& entry = request->ResultSet.emplace_back(); + entry.Path = SplitPath("/Root/SubDomain/DirA"); + entry.RequestType = TNavigate::TEntry::ERequestType::ByPath; + auto result = TestNavigateImpl(std::move(request), TNavigate::EStatus::PathErrorUnknown, + "", TNavigate::EOp::OpPath, false, true); + } + // error, by path id + { + auto request = MakeHolder<TNavigate>(); + request->DatabaseName = "/Root"; + auto& entry = request->ResultSet.emplace_back(); + entry.TableId = testId; + entry.RequestType = TNavigate::TEntry::ERequestType::ByTableId; + auto result = TestNavigateImpl(std::move(request), TNavigate::EStatus::PathErrorUnknown, + "", TNavigate::EOp::OpPath, false, true); + } +} + class TCacheTestWithDrops: public TCacheTest { public: TTestContext::TEventObserver ObserverFunc() override { diff --git a/ydb/core/tx/scheme_cache/scheme_cache.h b/ydb/core/tx/scheme_cache/scheme_cache.h index 06365155035..3e86fba52af 100644 --- a/ydb/core/tx/scheme_cache/scheme_cache.h +++ b/ydb/core/tx/scheme_cache/scheme_cache.h @@ -345,6 +345,7 @@ struct TSchemeCacheRequestContext : TAtomicRefCount<TSchemeCacheRequestContext>, ui64 WaitCounter; TAutoPtr<TSchemeCacheRequest> Request; const TInstant CreatedAt; + TIntrusivePtr<TDomainInfo> ResolvedDomainInfo; // resolved from DatabaseName TSchemeCacheRequestContext(const TActorId& sender, TAutoPtr<TSchemeCacheRequest> request, const TInstant& now = TInstant::Now()) : Sender(sender) @@ -359,6 +360,7 @@ struct TSchemeCacheNavigateContext : TAtomicRefCount<TSchemeCacheNavigateContext ui64 WaitCounter; TAutoPtr<TSchemeCacheNavigate> Request; const TInstant CreatedAt; + TIntrusivePtr<TDomainInfo> ResolvedDomainInfo; // resolved from DatabaseName TSchemeCacheNavigateContext(const TActorId& sender, TAutoPtr<TSchemeCacheNavigate> request, const TInstant& now = TInstant::Now()) : Sender(sender) diff --git a/ydb/tests/functional/tenants/test_dynamic_tenants.py b/ydb/tests/functional/tenants/test_dynamic_tenants.py index bdf7d597824..1ea37838e85 100644 --- a/ydb/tests/functional/tenants/test_dynamic_tenants.py +++ b/ydb/tests/functional/tenants/test_dynamic_tenants.py @@ -404,6 +404,6 @@ class TestCheckAccess(DBWithDynamicSlot): calling(client.list_directory).with_args( '/Root/' ), - raises(ydb.Unauthorized) + raises(ydb.SchemeError) ) client.list_directory('/') diff --git a/ydb/tests/functional/tenants/test_tenants.py b/ydb/tests/functional/tenants/test_tenants.py index 138297d8ccd..f295e8740d6 100644 --- a/ydb/tests/functional/tenants/test_tenants.py +++ b/ydb/tests/functional/tenants/test_tenants.py @@ -373,12 +373,6 @@ class TestTenants(DBForStaticSlots): assert len(result.children) > 0 assert result.children[0].name == ".sys" - result = driver.scheme_client.list_directory(above_database) - logger.debug("From database: list above database <%s> is %s", above_database, convert(result)) - assert len(result.children) > 0 - assert result.children[0].name == basename - assert result.children[0].type == ydb.scheme.SchemeEntryType.DATABASE - driver_config_for_root = ydb.DriverConfig( "%s:%s" % (self.cluster.nodes[1].host, self.cluster.nodes[1].port), self.root_dir |