Skip to content

Commit 6576464

Browse files
authored
Http authorization support (#5982)
1 parent e791eb9 commit 6576464

16 files changed

+539
-73
lines changed

ydb/core/grpc_services/base/base.h

Lines changed: 246 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

@@ -365,7 +377,7 @@ class IRequestProxyCtx
365377
virtual ~IRequestProxyCtx() = default;
366378

367379
// auth
368-
virtual const TMaybe<TString> GetYdbToken() const = 0;
380+
virtual const TMaybe<TString> GetYdbToken() const = 0;
369381
virtual void UpdateAuthState(NYdbGrpc::TAuthState::EAuthState state) = 0;
370382
virtual void SetInternalToken(const TIntrusiveConstPtr<NACLib::TUserToken>& token) = 0;
371383
virtual const NYdbGrpc::TAuthState& GetAuthState() const = 0;
@@ -1553,5 +1565,237 @@ class TGRpcRequestValidationWrapper
15531565
bool RlAllowed;
15541566
};
15551567

1568+
class TEvRequestAuthAndCheckResult : public TEventLocal<TEvRequestAuthAndCheckResult, TRpcServices::EvRequestAuthAndCheckResult> {
1569+
public:
1570+
TEvRequestAuthAndCheckResult(Ydb::StatusIds::StatusCode status, const NYql::TIssues& issues)
1571+
: Status(status)
1572+
, Issues(issues)
1573+
{}
1574+
1575+
TEvRequestAuthAndCheckResult(Ydb::StatusIds::StatusCode status, const NYql::TIssue& issue)
1576+
: Status(status)
1577+
{
1578+
Issues.AddIssue(issue);
1579+
}
1580+
1581+
TEvRequestAuthAndCheckResult(Ydb::StatusIds::StatusCode status, const TString& error)
1582+
: Status(status)
1583+
{
1584+
Issues.AddIssue(error);
1585+
}
1586+
1587+
TEvRequestAuthAndCheckResult(const TString& database, const TMaybe<TString>& ydbToken, const TIntrusiveConstPtr<NACLib::TUserToken>& userToken)
1588+
: Database(database)
1589+
, YdbToken(ydbToken)
1590+
, UserToken(userToken)
1591+
{}
1592+
1593+
Ydb::StatusIds::StatusCode Status = Ydb::StatusIds::SUCCESS;
1594+
NYql::TIssues Issues;
1595+
TString Database;
1596+
TMaybe<TString> YdbToken;
1597+
TIntrusiveConstPtr<NACLib::TUserToken> UserToken;
1598+
};
1599+
1600+
class TEvRequestAuthAndCheck
1601+
: public IRequestProxyCtx
1602+
, public TEventLocal<TEvRequestAuthAndCheck, TRpcServices::EvRequestAuthAndCheck> {
1603+
public:
1604+
TEvRequestAuthAndCheck(const TString& database, const TMaybe<TString>& ydbToken, NActors::TActorId sender)
1605+
: Database(database)
1606+
, YdbToken(ydbToken)
1607+
, Sender(sender)
1608+
, AuthState(true)
1609+
{}
1610+
1611+
// IRequestProxyCtx
1612+
const TMaybe<TString> GetYdbToken() const override {
1613+
return YdbToken;
1614+
}
1615+
1616+
void UpdateAuthState(NYdbGrpc::TAuthState::EAuthState state) override {
1617+
AuthState.State = state;
1618+
}
1619+
1620+
void SetInternalToken(const TIntrusiveConstPtr<NACLib::TUserToken>& token) override {
1621+
UserToken = token;
1622+
}
1623+
1624+
const NYdbGrpc::TAuthState& GetAuthState() const override {
1625+
return AuthState;
1626+
}
1627+
1628+
void ReplyUnauthenticated(const TString& msg = "") override {
1629+
if (msg) {
1630+
IssueManager.RaiseIssue(NYql::TIssue{msg});
1631+
}
1632+
ReplyWithYdbStatus(Ydb::StatusIds::UNAUTHORIZED);
1633+
}
1634+
1635+
void ReplyWithYdbStatus(Ydb::StatusIds::StatusCode status) override {
1636+
const NActors::TActorContext& ctx = NActors::TActivationContext::AsActorContext();
1637+
if (status == Ydb::StatusIds::SUCCESS) {
1638+
ctx.Send(Sender,
1639+
new TEvRequestAuthAndCheckResult(
1640+
Database,
1641+
YdbToken,
1642+
UserToken
1643+
)
1644+
);
1645+
} else {
1646+
ctx.Send(Sender,
1647+
new TEvRequestAuthAndCheckResult(
1648+
status,
1649+
IssueManager.GetIssues()
1650+
)
1651+
);
1652+
}
1653+
}
1654+
1655+
void RaiseIssue(const NYql::TIssue& issue) override {
1656+
IssueManager.RaiseIssue(issue);
1657+
}
1658+
1659+
void RaiseIssues(const NYql::TIssues& issues) override {
1660+
IssueManager.RaiseIssues(issues);
1661+
}
1662+
1663+
TVector<TStringBuf> FindClientCertPropertyValues() const override {
1664+
return {};
1665+
}
1666+
1667+
void StartTracing(NWilson::TSpan&& span) override {
1668+
Span = std::move(span);
1669+
}
1670+
void FinishSpan() override {
1671+
Span.End();
1672+
}
1673+
1674+
bool* IsTracingDecided() override {
1675+
return nullptr;
1676+
}
1677+
1678+
bool Validate(TString& /*error*/) override {
1679+
return true;
1680+
}
1681+
1682+
void SetCounters(IGRpcProxyCounters::TPtr counters) override {
1683+
Counters = std::move(counters);
1684+
}
1685+
1686+
IGRpcProxyCounters::TPtr GetCounters() const override {
1687+
return Counters;
1688+
}
1689+
1690+
void UseDatabase(const TString& database) override {
1691+
Database = database;
1692+
}
1693+
1694+
void SetRespHook(TRespHook&& /*hook*/) override {
1695+
}
1696+
1697+
void SetRlPath(TMaybe<NRpcService::TRlPath>&& path) override {
1698+
RlPath = std::move(path);
1699+
}
1700+
1701+
TRateLimiterMode GetRlMode() const override {
1702+
return TRateLimiterMode::Rps;
1703+
}
1704+
1705+
bool TryCustomAttributeProcess(const TSchemeBoardEvents::TDescribeSchemeResult& /*schemeData*/, ICheckerIface* /*iface*/) override {
1706+
return false;
1707+
}
1708+
1709+
void Pass(const IFacilityProvider& /*facility*/) override {
1710+
ReplyWithYdbStatus(Ydb::StatusIds::SUCCESS);
1711+
}
1712+
1713+
void SetAuditLogHook(TAuditLogHook&& /*hook*/) override {
1714+
}
1715+
1716+
void SetDiskQuotaExceeded(bool /*disk*/) override {
1717+
}
1718+
1719+
void AddAuditLogPart(const TStringBuf& name, const TString& value) override {
1720+
AuditLogParts.emplace_back(name, value);
1721+
}
1722+
1723+
const TAuditLogParts& GetAuditLogParts() const override {
1724+
return AuditLogParts;
1725+
}
1726+
1727+
TMaybe<TString> GetTraceId() const override {
1728+
return {};
1729+
}
1730+
1731+
NWilson::TTraceId GetWilsonTraceId() const override {
1732+
return Span.GetTraceId();
1733+
}
1734+
1735+
const TMaybe<TString> GetDatabaseName() const override {
1736+
return Database ? TMaybe<TString>(Database) : Nothing();
1737+
}
1738+
1739+
const TIntrusiveConstPtr<NACLib::TUserToken>& GetInternalToken() const override {
1740+
return UserToken;
1741+
}
1742+
1743+
const TString& GetSerializedToken() const override {
1744+
if (UserToken) {
1745+
return UserToken->GetSerializedToken();
1746+
}
1747+
1748+
return EmptySerializedTokenMessage;
1749+
}
1750+
1751+
bool IsClientLost() const override {
1752+
return false;
1753+
}
1754+
1755+
const TMaybe<TString> GetPeerMetaValues(const TString&) const override {
1756+
return {};
1757+
}
1758+
1759+
TString GetPeerName() const override {
1760+
return {};
1761+
}
1762+
1763+
const TString& GetRequestName() const override {
1764+
static TString str = "request auth and check internal request";
1765+
return str;
1766+
}
1767+
1768+
TMaybe<NRpcService::TRlPath> GetRlPath() const override {
1769+
return RlPath;
1770+
}
1771+
1772+
TInstant GetDeadline() const override {
1773+
return deadline;
1774+
}
1775+
1776+
1777+
TMaybe<TString> GetSdkBuildInfo() const {
1778+
return {};
1779+
}
1780+
1781+
TMaybe<TString> GetGrpcUserAgent() const {
1782+
return {};
1783+
}
1784+
1785+
TString Database;
1786+
TMaybe<TString> YdbToken;
1787+
NActors::TActorId Sender;
1788+
NYdbGrpc::TAuthState AuthState;
1789+
NWilson::TSpan Span;
1790+
IGRpcProxyCounters::TPtr Counters;
1791+
TMaybe<NRpcService::TRlPath> RlPath;
1792+
TAuditLogParts AuditLogParts;
1793+
NYql::TIssueManager IssueManager;
1794+
TIntrusiveConstPtr<NACLib::TUserToken> UserToken;
1795+
TInstant deadline = TInstant::Now() + TDuration::Seconds(10);
1796+
1797+
inline static const TString EmptySerializedTokenMessage;
1798+
};
1799+
15561800
} // namespace NGRpcService
15571801
} // namespace NKikimr

ydb/core/grpc_services/grpc_request_check_actor.h

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,20 @@ bool TGRpcRequestProxyHandleMethods::ValidateAndReplyOnError(TCtx* ctx) {
3838
}
3939
}
4040

41+
inline const TVector<TEvTicketParser::TEvAuthorizeTicket::TEntry>& GetEntriesForAuthAndCheckRequest(TEvRequestAuthAndCheck::TPtr& ev) {
42+
if (ev->Get()->YdbToken && ev->Get()->YdbToken->StartsWith("Bearer")) {
43+
if (AppData()->AuthConfig.GetUseAccessService()
44+
&& (AppData()->DomainsConfig.GetSecurityConfig().ViewerAllowedSIDsSize() > 0 || AppData()->DomainsConfig.GetSecurityConfig().MonitoringAllowedSIDsSize() > 0)) {
45+
static TVector<NKikimr::TEvTicketParser::TEvAuthorizeTicket::TEntry> entries = {
46+
{NKikimr::TEvTicketParser::TEvAuthorizeTicket::ToPermissions({"ydb.developerApi.get", "ydb.developerApi.update"}), {{"gizmo_id", "gizmo"}}}
47+
};
48+
return entries;
49+
}
50+
}
51+
static TVector<NKikimr::TEvTicketParser::TEvAuthorizeTicket::TEntry> emptyEntries = {};
52+
return emptyEntries;
53+
}
54+
4155
template <typename TEvent>
4256
class TGrpcRequestCheckActor
4357
: public TGRpcRequestProxyHandleMethods
@@ -73,7 +87,8 @@ class TGrpcRequestCheckActor
7387
}
7488

7589
void ProcessCommonAttributes(const TSchemeBoardEvents::TDescribeSchemeResult& schemeData) {
76-
static std::vector<TString> allowedAttributes = {"folder_id", "service_account_id", "database_id", "container_id"};
90+
TVector<TEvTicketParser::TEvAuthorizeTicket::TEntry> entries;
91+
static std::vector<TString> allowedAttributes = {"folder_id", "service_account_id", "database_id"};
7792
TVector<std::pair<TString, TString>> attributes;
7893
attributes.reserve(schemeData.GetPathDescription().UserAttributesSize());
7994
for (const auto& attr : schemeData.GetPathDescription().GetUserAttributes()) {
@@ -82,7 +97,16 @@ class TGrpcRequestCheckActor
8297
}
8398
}
8499
if (!attributes.empty()) {
85-
SetEntries({{GetPermissions(), attributes}});
100+
entries.emplace_back(GetPermissions(), attributes);
101+
}
102+
103+
if constexpr (std::is_same_v<TEvent, TEvRequestAuthAndCheck>) {
104+
const auto& e = GetEntriesForAuthAndCheckRequest(Request_);
105+
entries.insert(entries.end(), e.begin(), e.end());
106+
}
107+
108+
if (!entries.empty()) {
109+
SetEntries(entries);
86110
}
87111
}
88112

@@ -464,6 +488,12 @@ class TGrpcRequestCheckActor
464488
ReplyBackAndDie();
465489
}
466490

491+
void HandleAndDie(TEvRequestAuthAndCheck::TPtr& ev) {
492+
GrpcRequestBaseCtx_->FinishSpan();
493+
ev->Get()->ReplyWithYdbStatus(Ydb::StatusIds::SUCCESS);
494+
PassAway();
495+
}
496+
467497
template <typename T>
468498
void HandleAndDie(T& event) {
469499
GrpcRequestBaseCtx_->FinishSpan();

ydb/core/grpc_services/grpc_request_proxy.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ class TGRpcRequestProxyImpl
117117
NYql::TIssues()});
118118
}
119119

120+
void Handle(TEvRequestAuthAndCheck::TPtr& ev, const TActorContext&) {
121+
ev->Get()->FinishSpan();
122+
ev->Get()->ReplyWithYdbStatus(Ydb::StatusIds::SUCCESS);
123+
}
124+
120125
// returns true and defer event if no updates for given database
121126
// otherwice returns false and leave event untouched
122127
template <typename TEvent>
@@ -186,7 +191,7 @@ class TGRpcRequestProxyImpl
186191
if (maybeDatabaseName && !maybeDatabaseName.GetRef().empty()) {
187192
databaseName = CanonizePath(maybeDatabaseName.GetRef());
188193
} else {
189-
if (!AllowYdbRequestsWithoutDatabase && DynamicNode) {
194+
if (!AllowYdbRequestsWithoutDatabase && DynamicNode && !std::is_same_v<TEvent, TEvRequestAuthAndCheck>) { // TEvRequestAuthAndCheck is allowed to be processed without database
190195
requestBaseCtx->ReplyUnauthenticated("Requests without specified database are not allowed");
191196
requestBaseCtx->FinishSpan();
192197
return;
@@ -590,6 +595,7 @@ void TGRpcRequestProxyImpl::StateFunc(TAutoPtr<IEventHandle>& ev) {
590595
HFunc(TEvCoordinationSessionRequest, PreHandle);
591596
HFunc(TEvNodeCheckRequest, PreHandle);
592597
HFunc(TEvProxyRuntimeEvent, PreHandle);
598+
HFunc(TEvRequestAuthAndCheck, PreHandle);
593599

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

ydb/core/grpc_services/grpc_request_proxy.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,15 +57,5 @@ class TGRpcRequestProxy : public TGRpcRequestProxyHandleMethods, public IFacilit
5757
TActorId DiscoveryCacheActorID;
5858
};
5959

60-
inline TActorId CreateGRpcRequestProxyId(int n = 0) {
61-
if (n == 0) {
62-
const auto actorId = TActorId(0, "GRpcReqProxy");
63-
return actorId;
64-
}
65-
66-
const auto actorId = TActorId(0, TStringBuilder() << "GRpcReqPro" << n);
67-
return actorId;
68-
}
69-
7060
} // namespace NGRpcService
7161
} // namespace NKikimr

0 commit comments

Comments
 (0)