Skip to content

Commit ef7b8bc

Browse files
[Merge to 24-2] Http authorization support (#6422)
Co-authored-by: Pisarenko Grigoriy <[email protected]>
1 parent 2f4c86d commit ef7b8bc

15 files changed

+573
-77
lines changed

ydb/core/grpc_services/base/base.h

Lines changed: 272 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,16 @@ using TYdbIssueMessageType = Ydb::Issue::IssueMessage;
5151
std::pair<TString, TString> SplitPath(const TMaybe<TString>& database, const TString& path);
5252
std::pair<TString, TString> SplitPath(const TString& path);
5353

54+
inline TActorId CreateGRpcRequestProxyId(int n = 0) {
55+
if (n == 0) {
56+
const auto actorId = TActorId(0, "GRpcReqProxy");
57+
return actorId;
58+
}
59+
60+
const auto actorId = TActorId(0, TStringBuilder() << "GRpcReqPro" << n);
61+
return actorId;
62+
}
63+
5464
struct TRpcServices {
5565
enum EServiceId {
5666
EvMakeDirectory = EventSpaceBegin(TKikimrEvents::ES_GRPC_CALLS),
@@ -224,7 +234,9 @@ struct TRpcServices {
224234
EvAcquireYndxRateLimiterResource,
225235
EvGrpcRuntimeRequest,
226236
EvNodeCheckRequest,
227-
EvStreamWriteRefreshToken // internal call, pair to EvRefreshToken
237+
EvStreamWriteRefreshToken, // internal call, pair to EvRefreshToken
238+
EvRequestAuthAndCheck, // performs authorization and runs GrpcRequestCheckActor
239+
EvRequestAuthAndCheckResult,
228240
// !!! DO NOT ADD NEW REQUEST !!!
229241
};
230242

@@ -359,7 +371,7 @@ class IRequestProxyCtx : public virtual IRequestCtxBase {
359371
virtual ~IRequestProxyCtx() = default;
360372

361373
// auth
362-
virtual const TMaybe<TString> GetYdbToken() const = 0;
374+
virtual const TMaybe<TString> GetYdbToken() const = 0;
363375
virtual void UpdateAuthState(NYdbGrpc::TAuthState::EAuthState state) = 0;
364376
virtual void SetInternalToken(const TIntrusiveConstPtr<NACLib::TUserToken>& token) = 0;
365377
virtual const NYdbGrpc::TAuthState& GetAuthState() const = 0;
@@ -1591,5 +1603,263 @@ class TGRpcRequestValidationWrapper
15911603
bool RlAllowed;
15921604
};
15931605

1606+
class TEvRequestAuthAndCheckResult : public TEventLocal<TEvRequestAuthAndCheckResult, TRpcServices::EvRequestAuthAndCheckResult> {
1607+
public:
1608+
TEvRequestAuthAndCheckResult(Ydb::StatusIds::StatusCode status, const NYql::TIssues& issues)
1609+
: Status(status)
1610+
, Issues(issues)
1611+
{}
1612+
1613+
TEvRequestAuthAndCheckResult(Ydb::StatusIds::StatusCode status, const NYql::TIssue& issue)
1614+
: Status(status)
1615+
{
1616+
Issues.AddIssue(issue);
1617+
}
1618+
1619+
TEvRequestAuthAndCheckResult(Ydb::StatusIds::StatusCode status, const TString& error)
1620+
: Status(status)
1621+
{
1622+
Issues.AddIssue(error);
1623+
}
1624+
1625+
TEvRequestAuthAndCheckResult(const TString& database, const TMaybe<TString>& ydbToken, const TIntrusiveConstPtr<NACLib::TUserToken>& userToken)
1626+
: Database(database)
1627+
, YdbToken(ydbToken)
1628+
, UserToken(userToken)
1629+
{}
1630+
1631+
Ydb::StatusIds::StatusCode Status = Ydb::StatusIds::SUCCESS;
1632+
NYql::TIssues Issues;
1633+
TString Database;
1634+
TMaybe<TString> YdbToken;
1635+
TIntrusiveConstPtr<NACLib::TUserToken> UserToken;
1636+
};
1637+
1638+
class TEvRequestAuthAndCheck
1639+
: public IRequestProxyCtx
1640+
, public TEventLocal<TEvRequestAuthAndCheck, TRpcServices::EvRequestAuthAndCheck> {
1641+
public:
1642+
TEvRequestAuthAndCheck(const TString& database, const TMaybe<TString>& ydbToken, NActors::TActorId sender)
1643+
: Database(database)
1644+
, YdbToken(ydbToken)
1645+
, Sender(sender)
1646+
, AuthState(true)
1647+
{}
1648+
1649+
// IRequestProxyCtx
1650+
const TMaybe<TString> GetYdbToken() const override {
1651+
return YdbToken;
1652+
}
1653+
1654+
void UpdateAuthState(NYdbGrpc::TAuthState::EAuthState state) override {
1655+
AuthState.State = state;
1656+
}
1657+
1658+
void SetInternalToken(const TIntrusiveConstPtr<NACLib::TUserToken>& token) override {
1659+
UserToken = token;
1660+
}
1661+
1662+
const NYdbGrpc::TAuthState& GetAuthState() const override {
1663+
return AuthState;
1664+
}
1665+
1666+
void ReplyUnauthenticated(const TString& msg = "") override {
1667+
if (msg) {
1668+
IssueManager.RaiseIssue(NYql::TIssue{msg});
1669+
}
1670+
ReplyWithYdbStatus(Ydb::StatusIds::UNAUTHORIZED);
1671+
}
1672+
1673+
void ReplyWithYdbStatus(Ydb::StatusIds::StatusCode status) override {
1674+
const NActors::TActorContext& ctx = NActors::TActivationContext::AsActorContext();
1675+
if (status == Ydb::StatusIds::SUCCESS) {
1676+
ctx.Send(Sender,
1677+
new TEvRequestAuthAndCheckResult(
1678+
Database,
1679+
YdbToken,
1680+
UserToken
1681+
)
1682+
);
1683+
} else {
1684+
ctx.Send(Sender,
1685+
new TEvRequestAuthAndCheckResult(
1686+
status,
1687+
IssueManager.GetIssues()
1688+
)
1689+
);
1690+
}
1691+
}
1692+
1693+
void ReplyWithRpcStatus(grpc::StatusCode code, const TString& reason, const TString& details) override {
1694+
Y_UNUSED(code);
1695+
if (reason) {
1696+
IssueManager.RaiseIssue(NYql::TIssue{reason});
1697+
}
1698+
if (details) {
1699+
IssueManager.RaiseIssue(NYql::TIssue{details});
1700+
}
1701+
ReplyWithYdbStatus(Ydb::StatusIds::GENERIC_ERROR);
1702+
}
1703+
1704+
void ReplyUnavaliable() override {
1705+
ReplyWithYdbStatus(Ydb::StatusIds::UNAVAILABLE);
1706+
}
1707+
1708+
void RaiseIssue(const NYql::TIssue& issue) override {
1709+
IssueManager.RaiseIssue(issue);
1710+
}
1711+
1712+
void RaiseIssues(const NYql::TIssues& issues) override {
1713+
IssueManager.RaiseIssues(issues);
1714+
}
1715+
1716+
TVector<TStringBuf> FindClientCertPropertyValues() const override {
1717+
return {};
1718+
}
1719+
1720+
void StartTracing(NWilson::TSpan&& span) override {
1721+
Span = std::move(span);
1722+
}
1723+
void FinishSpan() override {
1724+
Span.End();
1725+
}
1726+
1727+
bool* IsTracingDecided() override {
1728+
return nullptr;
1729+
}
1730+
1731+
bool Validate(TString& /*error*/) override {
1732+
return true;
1733+
}
1734+
1735+
void SetCounters(IGRpcProxyCounters::TPtr counters) override {
1736+
Counters = std::move(counters);
1737+
}
1738+
1739+
IGRpcProxyCounters::TPtr GetCounters() const override {
1740+
return Counters;
1741+
}
1742+
1743+
bool HasClientCapability(const TString&) const override {
1744+
return false;
1745+
}
1746+
1747+
void UseDatabase(const TString& database) override {
1748+
Database = database;
1749+
}
1750+
1751+
void SetRespHook(TRespHook&& /*hook*/) override {
1752+
}
1753+
1754+
void SetRlPath(TMaybe<NRpcService::TRlPath>&& path) override {
1755+
RlPath = std::move(path);
1756+
}
1757+
1758+
TRateLimiterMode GetRlMode() const override {
1759+
return TRateLimiterMode::Rps;
1760+
}
1761+
1762+
bool TryCustomAttributeProcess(const TSchemeBoardEvents::TDescribeSchemeResult& /*schemeData*/, ICheckerIface* /*iface*/) override {
1763+
return false;
1764+
}
1765+
1766+
void Pass(const IFacilityProvider& /*facility*/) override {
1767+
ReplyWithYdbStatus(Ydb::StatusIds::SUCCESS);
1768+
}
1769+
1770+
void SetAuditLogHook(TAuditLogHook&& /*hook*/) override {
1771+
}
1772+
1773+
void SetDiskQuotaExceeded(bool /*disk*/) override {
1774+
}
1775+
1776+
void AddAuditLogPart(const TStringBuf& name, const TString& value) override {
1777+
AuditLogParts.emplace_back(name, value);
1778+
}
1779+
1780+
const TAuditLogParts& GetAuditLogParts() const override {
1781+
return AuditLogParts;
1782+
}
1783+
1784+
TMaybe<TString> GetTraceId() const override {
1785+
return {};
1786+
}
1787+
1788+
NWilson::TTraceId GetWilsonTraceId() const override {
1789+
return Span.GetTraceId();
1790+
}
1791+
1792+
const TMaybe<TString> GetDatabaseName() const override {
1793+
return Database ? TMaybe<TString>(Database) : Nothing();
1794+
}
1795+
1796+
const TIntrusiveConstPtr<NACLib::TUserToken>& GetInternalToken() const override {
1797+
return UserToken;
1798+
}
1799+
1800+
const TString& GetSerializedToken() const override {
1801+
if (UserToken) {
1802+
return UserToken->GetSerializedToken();
1803+
}
1804+
1805+
return EmptySerializedTokenMessage;
1806+
}
1807+
1808+
bool IsClientLost() const override {
1809+
return false;
1810+
}
1811+
1812+
const TMaybe<TString> GetPeerMetaValues(const TString&) const override {
1813+
return {};
1814+
}
1815+
1816+
TString GetPeerName() const override {
1817+
return {};
1818+
}
1819+
1820+
const TString& GetRequestName() const override {
1821+
static TString str = "request auth and check internal request";
1822+
return str;
1823+
}
1824+
1825+
TMaybe<NRpcService::TRlPath> GetRlPath() const override {
1826+
return RlPath;
1827+
}
1828+
1829+
TInstant GetDeadline() const override {
1830+
return deadline;
1831+
}
1832+
1833+
bool GetDiskQuotaExceeded() const override {
1834+
return false;
1835+
}
1836+
1837+
TMaybe<TString> GetSdkBuildInfo() const {
1838+
return {};
1839+
}
1840+
1841+
TMaybe<TString> GetGrpcUserAgent() const {
1842+
return {};
1843+
}
1844+
1845+
TVector<TStringBuf> FindClientCert() const override {
1846+
return {};
1847+
}
1848+
1849+
TString Database;
1850+
TMaybe<TString> YdbToken;
1851+
NActors::TActorId Sender;
1852+
NYdbGrpc::TAuthState AuthState;
1853+
NWilson::TSpan Span;
1854+
IGRpcProxyCounters::TPtr Counters;
1855+
TMaybe<NRpcService::TRlPath> RlPath;
1856+
TAuditLogParts AuditLogParts;
1857+
NYql::TIssueManager IssueManager;
1858+
TIntrusiveConstPtr<NACLib::TUserToken> UserToken;
1859+
TInstant deadline = TInstant::Now() + TDuration::Seconds(10);
1860+
1861+
inline static const TString EmptySerializedTokenMessage;
1862+
};
1863+
15941864
} // namespace NGRpcService
15951865
} // namespace NKikimr

ydb/core/grpc_services/grpc_request_check_actor.h

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,20 @@
2424
namespace NKikimr {
2525
namespace NGRpcService {
2626

27+
inline const TVector<TEvTicketParser::TEvAuthorizeTicket::TEntry>& GetEntriesForAuthAndCheckRequest(TEvRequestAuthAndCheck::TPtr& ev) {
28+
if (ev->Get()->YdbToken && ev->Get()->YdbToken->StartsWith("Bearer")) {
29+
if (AppData()->AuthConfig.GetUseAccessService()
30+
&& (AppData()->DomainsConfig.GetSecurityConfig().ViewerAllowedSIDsSize() > 0 || AppData()->DomainsConfig.GetSecurityConfig().MonitoringAllowedSIDsSize() > 0)) {
31+
static TVector<NKikimr::TEvTicketParser::TEvAuthorizeTicket::TEntry> entries = {
32+
{NKikimr::TEvTicketParser::TEvAuthorizeTicket::ToPermissions({"ydb.developerApi.get", "ydb.developerApi.update"}), {{"gizmo_id", "gizmo"}}}
33+
};
34+
return entries;
35+
}
36+
}
37+
static TVector<NKikimr::TEvTicketParser::TEvAuthorizeTicket::TEntry> emptyEntries = {};
38+
return emptyEntries;
39+
}
40+
2741
template <typename TEvent>
2842
class TGrpcRequestCheckActor
2943
: public TGRpcRequestProxyHandleMethods
@@ -59,6 +73,7 @@ class TGrpcRequestCheckActor
5973
}
6074

6175
void ProcessCommonAttributes(const TSchemeBoardEvents::TDescribeSchemeResult& schemeData) {
76+
TVector<TEvTicketParser::TEvAuthorizeTicket::TEntry> entries;
6277
static std::vector<TString> allowedAttributes = {"folder_id", "service_account_id", "database_id"};
6378
TVector<std::pair<TString, TString>> attributes;
6479
attributes.reserve(schemeData.GetPathDescription().UserAttributesSize());
@@ -68,7 +83,16 @@ class TGrpcRequestCheckActor
6883
}
6984
}
7085
if (!attributes.empty()) {
71-
SetEntries({{GetPermissions(), attributes}});
86+
entries.emplace_back(GetPermissions(), attributes);
87+
}
88+
89+
if constexpr (std::is_same_v<TEvent, TEvRequestAuthAndCheck>) {
90+
const auto& e = GetEntriesForAuthAndCheckRequest(Request_);
91+
entries.insert(entries.end(), e.begin(), e.end());
92+
}
93+
94+
if (!entries.empty()) {
95+
SetEntries(entries);
7296
}
7397
}
7498

@@ -450,6 +474,12 @@ class TGrpcRequestCheckActor
450474
ReplyBackAndDie();
451475
}
452476

477+
void HandleAndDie(TEvRequestAuthAndCheck::TPtr& ev) {
478+
GrpcRequestBaseCtx_->FinishSpan();
479+
ev->Get()->ReplyWithYdbStatus(Ydb::StatusIds::SUCCESS);
480+
PassAway();
481+
}
482+
453483
template <typename T>
454484
void HandleAndDie(T& event) {
455485
GrpcRequestBaseCtx_->FinishSpan();

ydb/core/grpc_services/grpc_request_proxy.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@ class TGRpcRequestProxyImpl
119119
NYql::TIssues()});
120120
}
121121

122+
void Handle(TEvRequestAuthAndCheck::TPtr& ev, const TActorContext&) {
123+
ev->Get()->FinishSpan();
124+
ev->Get()->ReplyWithYdbStatus(Ydb::StatusIds::SUCCESS);
125+
}
126+
122127
// returns true and defer event if no updates for given database
123128
// otherwice returns false and leave event untouched
124129
template <typename TEvent>
@@ -188,8 +193,8 @@ class TGRpcRequestProxyImpl
188193
if (maybeDatabaseName && !maybeDatabaseName.GetRef().empty()) {
189194
databaseName = CanonizePath(maybeDatabaseName.GetRef());
190195
} else {
191-
if (!AllowYdbRequestsWithoutDatabase && DynamicNode) {
192-
requestBaseCtx->ReplyUnauthenticated("Requests without specified database is not allowed");
196+
if (!AllowYdbRequestsWithoutDatabase && DynamicNode && !std::is_same_v<TEvent, TEvRequestAuthAndCheck>) { // TEvRequestAuthAndCheck is allowed to be processed without database
197+
requestBaseCtx->ReplyUnauthenticated("Requests without specified database are not allowed");
193198
requestBaseCtx->FinishSpan();
194199
return;
195200
} else {
@@ -593,6 +598,7 @@ void TGRpcRequestProxyImpl::StateFunc(TAutoPtr<IEventHandle>& ev) {
593598
HFunc(TEvCoordinationSessionRequest, PreHandle);
594599
HFunc(TEvNodeCheckRequest, PreHandle);
595600
HFunc(TEvProxyRuntimeEvent, PreHandle);
601+
HFunc(TEvRequestAuthAndCheck, PreHandle);
596602

597603
default:
598604
Y_ABORT("Unknown request: %u\n", ev->GetTypeRewrite());

0 commit comments

Comments
 (0)