Skip to content

Commit 3cc117e

Browse files
Merge 18ba292 into e92e224
2 parents e92e224 + 18ba292 commit 3cc117e

32 files changed

+938
-284
lines changed

ydb/mvp/oidc_proxy/context.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
#include "oidc_settings.h"
88
#include "context.h"
99

10-
namespace NMVP {
11-
namespace NOIDC {
10+
namespace NMVP::NOIDC {
1211

1312
TContext::TContext(const TInitializer& initializer)
1413
: State(initializer.State)
@@ -94,5 +93,4 @@ TStringBuf TContext::GetRequestedUrl(const NHttp::THttpIncomingRequestPtr& reque
9493
return requestedUrl;
9594
}
9695

97-
} // NOIDC
98-
} // NMVP
96+
} // NMVP::NOIDC

ydb/mvp/oidc_proxy/context.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ using THttpIncomingRequestPtr = TIntrusivePtr<THttpIncomingRequest>;
1010

1111
}
1212

13-
namespace NMVP {
14-
namespace NOIDC {
13+
namespace NMVP::NOIDC {
1514

1615
class TContext {
1716
public:
@@ -45,5 +44,4 @@ class TContext {
4544
TString GenerateCookie(const TString& key) const;
4645
};
4746

48-
} // NOIDC
49-
} // NMVP
47+
} // NMVP::NOIDC

ydb/mvp/oidc_proxy/mvp.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@
2828

2929
NActors::IActor* CreateMemProfiler();
3030

31-
namespace NMVP {
32-
namespace NOIDC {
31+
namespace NMVP::NOIDC {
3332

3433
namespace {
3534

@@ -233,6 +232,7 @@ void TMVP::TryGetOidcOptionsFromConfig(const YAML::Node& config) {
233232
OpenIdConnectSettings.AuthUrlPath = oidc["auth_url_path"].as<std::string>(OpenIdConnectSettings.DEFAULT_AUTH_URL_PATH);
234233
OpenIdConnectSettings.TokenUrlPath = oidc["token_url_path"].as<std::string>(OpenIdConnectSettings.DEFAULT_TOKEN_URL_PATH);
235234
OpenIdConnectSettings.ExchangeUrlPath = oidc["exchange_url_path"].as<std::string>(OpenIdConnectSettings.DEFAULT_EXCHANGE_URL_PATH);
235+
OpenIdConnectSettings.ImpersonateUrlPath = oidc["impersonate_url_path"].as<std::string>(OpenIdConnectSettings.DEFAULT_IMPERSONATE_URL_PATH);
236236
Cout << "Started processing allowed_proxy_hosts..." << Endl;
237237
for (const std::string& host : oidc["allowed_proxy_hosts"].as<std::vector<std::string>>()) {
238238
Cout << host << " added to allowed_proxy_hosts" << Endl;
@@ -417,5 +417,4 @@ THolder<NActors::TActorSystemSetup> TMVP::BuildActorSystemSetup(int argc, char**
417417

418418
TAtomic TMVP::Quit = false;
419419

420-
} // NOIDC
421-
} // NMVP
420+
} // NMVP::NOIDC

ydb/mvp/oidc_proxy/mvp.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
#include <contrib/libs/yaml-cpp/include/yaml-cpp/yaml.h>
1313
#include "oidc_settings.h"
1414

15-
namespace NMVP {
16-
namespace NOIDC {
15+
namespace NMVP::NOIDC {
1716

1817
const TString& GetEServiceName(NActors::NLog::EComponent component);
1918

@@ -72,5 +71,4 @@ class TMVP {
7271
int Shutdown();
7372
};
7473

75-
} // namespace NOIDC
76-
} // namespace NMVP
74+
} // NMVP::NOIDC

ydb/mvp/oidc_proxy/oidc_client.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
#include "oidc_client.h"
22
#include "oidc_protected_page_handler.h"
33
#include "oidc_session_create_handler.h"
4+
#include "oidc_impersonate_start_page_nebius.h"
5+
#include "oidc_impersonate_stop_page_nebius.h"
46

5-
namespace NMVP {
6-
namespace NOIDC {
7+
namespace NMVP::NOIDC {
8+
9+
using namespace NActors;
710

811
void InitOIDC(NActors::TActorSystem& actorSystem,
912
const NActors::TActorId& httpProxyId,
@@ -14,12 +17,25 @@ void InitOIDC(NActors::TActorSystem& actorSystem,
1417
)
1518
);
1619

20+
if (settings.AccessServiceType == NMvp::nebius_v1) {
21+
actorSystem.Send(httpProxyId, new NHttp::TEvHttpProxy::TEvRegisterHandler(
22+
"/impersonate/start",
23+
actorSystem.Register(new TImpersonateStartPageHandler(httpProxyId, settings))
24+
)
25+
);
26+
27+
actorSystem.Send(httpProxyId, new NHttp::TEvHttpProxy::TEvRegisterHandler(
28+
"/impersonate/stop",
29+
actorSystem.Register(new TImpersonateStopPageHandler(httpProxyId, settings))
30+
)
31+
);
32+
}
33+
1734
actorSystem.Send(httpProxyId, new NHttp::TEvHttpProxy::TEvRegisterHandler(
1835
"/",
1936
actorSystem.Register(new TProtectedPageHandler(httpProxyId, settings))
2037
)
2138
);
2239
}
2340

24-
} // NOIDC
25-
} // NMVP
41+
} // NMVP::NOIDC

ydb/mvp/oidc_proxy/oidc_client.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@ class TActorSystem;
55
struct TActorId;
66

77
} // NActors
8-
namespace NMVP {
9-
namespace NOIDC {
8+
namespace NMVP::NOIDC {
109

1110
struct TOpenIdConnectSettings;
1211

1312
void InitOIDC(NActors::TActorSystem& actorSystem, const NActors::TActorId& httpProxyId, const TOpenIdConnectSettings& settings);
1413

15-
} // NOIDC
16-
} // NMVP
14+
} // NMVP::NOIDC
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#include <library/cpp/string_utils/base64/base64.h>
2+
#include <library/cpp/string_utils/quote/quote.h>
3+
#include <ydb/library/actors/http/http.h>
4+
#include <ydb/library/security/util.h>
5+
#include <ydb/mvp/core/mvp_log.h>
6+
#include <ydb/mvp/core/mvp_tokens.h>
7+
#include "openid_connect.h"
8+
#include "oidc_session_create.h"
9+
#include "oidc_impersonate_start_page_nebius.h"
10+
11+
namespace NMVP::NOIDC {
12+
13+
THandlerImpersonateStart::THandlerImpersonateStart(const NActors::TActorId& sender,
14+
const NHttp::THttpIncomingRequestPtr& request,
15+
const NActors::TActorId& httpProxyId,
16+
const TOpenIdConnectSettings& settings)
17+
: Sender(sender)
18+
, Request(request)
19+
, HttpProxyId(httpProxyId)
20+
, Settings(settings)
21+
{}
22+
23+
void THandlerImpersonateStart::Bootstrap(const NActors::TActorContext& ctx) {
24+
BLOG_D("Start impersonation process");
25+
26+
NHttp::TUrlParameters urlParameters(Request->URL);
27+
TString serviceAccountId = urlParameters["service_account_id"];
28+
29+
NHttp::THeaders headers(Request->Headers);
30+
NHttp::TCookies cookies(headers.Get("Cookie"));
31+
32+
TString sessionCookieName = CreateNameSessionCookie(Settings.ClientId);
33+
TStringBuf sessionCookieValue = cookies.Get(sessionCookieName);
34+
if (!sessionCookieValue.Empty()) {
35+
BLOG_D("Using session cookie (" << sessionCookieName << ": " << NKikimr::MaskTicket(sessionCookieValue) << ")");
36+
}
37+
TString sessionToken = DecodeToken(sessionCookieValue);
38+
TStringBuf impersonatedCookieValue = GetCookie(cookies, CreateNameImpersonatedCookie(Settings.ClientId));
39+
40+
if (sessionToken.empty()) {
41+
return ReplyBadRequestAndPassAway("Wrong impersonate parameter: session cookie not found");
42+
}
43+
if (!impersonatedCookieValue.empty()) {
44+
return ReplyBadRequestAndPassAway("Wrong impersonate parameter: impersonated cookie already exists");
45+
}
46+
if (serviceAccountId.empty()) {
47+
return ReplyBadRequestAndPassAway("Wrong impersonate parameter: service_account_id not found");
48+
}
49+
50+
RequestImpersonatedToken(sessionToken, serviceAccountId, ctx);
51+
}
52+
53+
void THandlerImpersonateStart::RequestImpersonatedToken(TString& sessionToken, TString& serviceAccountId, const NActors::TActorContext& ctx) {
54+
BLOG_D("Request impersonated token");
55+
NHttp::THttpOutgoingRequestPtr httpRequest = NHttp::THttpOutgoingRequest::CreateRequestPost(Settings.GetImpersonateEndpointURL());
56+
httpRequest->Set<&NHttp::THttpRequest::ContentType>("application/x-www-form-urlencoded");
57+
58+
TMvpTokenator* tokenator = MVPAppData()->Tokenator;
59+
TString token = "";
60+
if (tokenator) {
61+
token = tokenator->GetToken(Settings.SessionServiceTokenName);
62+
}
63+
httpRequest->Set("Authorization", token); // Bearer included
64+
65+
CGIEscape(sessionToken);
66+
CGIEscape(serviceAccountId);
67+
TStringBuilder body;
68+
body << "session=" << sessionToken
69+
<< "&service_account_id=" << serviceAccountId;
70+
httpRequest->Set<&NHttp::THttpRequest::Body>(body);
71+
72+
ctx.Send(HttpProxyId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest(httpRequest));
73+
Become(&THandlerImpersonateStart::StateWork);
74+
}
75+
76+
void THandlerImpersonateStart::ProcessImpersonatedToken(const TString& impersonatedToken) {
77+
TString impersonatedCookieName = CreateNameImpersonatedCookie(Settings.ClientId);
78+
TString impersonatedCookieValue = Base64Encode(impersonatedToken);
79+
BLOG_D("Set impersonated cookie: (" << impersonatedCookieName << ": " << NKikimr::MaskTicket(impersonatedCookieValue) << ")");
80+
81+
NHttp::THeadersBuilder responseHeaders;
82+
responseHeaders.Set("Set-Cookie", CreateSecureCookie(impersonatedCookieName, impersonatedCookieValue));
83+
SetCORS(Request, &responseHeaders);
84+
NHttp::THttpOutgoingResponsePtr httpResponse = Request->CreateResponse("200", "OK", responseHeaders);
85+
ReplyAndPassAway(httpResponse);
86+
}
87+
88+
void THandlerImpersonateStart::Handle(NHttp::TEvHttpProxy::TEvHttpIncomingResponse::TPtr event) {
89+
NHttp::THttpOutgoingResponsePtr httpResponse;
90+
if (event->Get()->Error.empty() && event->Get()->Response) {
91+
NHttp::THttpIncomingResponsePtr response = event->Get()->Response;
92+
BLOG_D("Incoming response from authorization server: " << response->Status);
93+
if (response->Status == "200") {
94+
TStringBuf errorMessage;
95+
NJson::TJsonValue jsonValue;
96+
NJson::TJsonReaderConfig jsonConfig;
97+
if (NJson::ReadJsonTree(response->Body, &jsonConfig, &jsonValue)) {
98+
const NJson::TJsonValue* jsonImpersonatedToken;
99+
if (jsonValue.GetValuePointer("impersonation", &jsonImpersonatedToken)) {
100+
TString impersonatedToken = jsonImpersonatedToken->GetStringRobust();
101+
ProcessImpersonatedToken(impersonatedToken);
102+
return;
103+
} else {
104+
errorMessage = "Wrong OIDC provider response: impersonated token not found";
105+
}
106+
} else {
107+
errorMessage = "Wrong OIDC response";
108+
}
109+
NHttp::THeadersBuilder responseHeaders;
110+
responseHeaders.Set("Content-Type", "text/plain");
111+
SetCORS(Request, &responseHeaders);
112+
return ReplyAndPassAway(Request->CreateResponse("400", "Bad Request", responseHeaders, errorMessage));
113+
} else {
114+
NHttp::THeadersBuilder responseHeaders;
115+
NHttp::THeaders headers(response->Headers);
116+
if (headers.Has("Content-Type")) {
117+
responseHeaders.Set("Content-Type", headers.Get("Content-Type"));
118+
}
119+
SetCORS(Request, &responseHeaders);
120+
return ReplyAndPassAway(Request->CreateResponse(response->Status, response->Message, responseHeaders, response->Body));
121+
}
122+
} else {
123+
NHttp::THeadersBuilder responseHeaders;
124+
responseHeaders.Set("Content-Type", "text/plain");
125+
SetCORS(Request, &responseHeaders);
126+
return ReplyAndPassAway(Request->CreateResponse("400", "Bad Request", responseHeaders, event->Get()->Error));
127+
}
128+
}
129+
130+
void THandlerImpersonateStart::ReplyAndPassAway(NHttp::THttpOutgoingResponsePtr httpResponse) {
131+
Send(Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(httpResponse));
132+
PassAway();
133+
}
134+
135+
void THandlerImpersonateStart::ReplyBadRequestAndPassAway(const TString& errorMessage) {
136+
NHttp::THeadersBuilder responseHeaders;
137+
responseHeaders.Set("Content-Type", "text/plain");
138+
SetCORS(Request, &responseHeaders);
139+
NHttp::THttpOutgoingResponsePtr httpResponse = Request->CreateResponse("400", "Bad Request", responseHeaders, errorMessage);
140+
ReplyAndPassAway(httpResponse);
141+
}
142+
143+
TImpersonateStartPageHandler::TImpersonateStartPageHandler(const NActors::TActorId& httpProxyId, const TOpenIdConnectSettings& settings)
144+
: TBase(&TImpersonateStartPageHandler::StateWork)
145+
, HttpProxyId(httpProxyId)
146+
, Settings(settings)
147+
{}
148+
149+
void TImpersonateStartPageHandler::Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx) {
150+
ctx.Register(new THandlerImpersonateStart(event->Sender, event->Get()->Request, HttpProxyId, Settings));
151+
}
152+
153+
} // NMVP::NOIDC
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#pragma once
2+
3+
#include "oidc_settings.h"
4+
#include "context.h"
5+
6+
namespace NMVP::NOIDC {
7+
8+
using namespace NActors;
9+
10+
class THandlerImpersonateStart : public NActors::TActorBootstrapped<THandlerImpersonateStart> {
11+
private:
12+
using TBase = NActors::TActorBootstrapped<THandlerImpersonateStart>;
13+
14+
protected:
15+
const NActors::TActorId Sender;
16+
const NHttp::THttpIncomingRequestPtr Request;
17+
const NActors::TActorId HttpProxyId;
18+
const TOpenIdConnectSettings Settings;
19+
20+
public:
21+
THandlerImpersonateStart(const NActors::TActorId& sender,
22+
const NHttp::THttpIncomingRequestPtr& request,
23+
const NActors::TActorId& httpProxyId,
24+
const TOpenIdConnectSettings& settings);
25+
void Bootstrap(const NActors::TActorContext& ctx);
26+
void RequestImpersonatedToken(TString&, TString&, const NActors::TActorContext&);
27+
void ProcessImpersonatedToken(const TString& impersonatedToken);
28+
void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingResponse::TPtr event);
29+
void ReplyAndPassAway(NHttp::THttpOutgoingResponsePtr httpResponse);
30+
void ReplyBadRequestAndPassAway(const TString& errorMessage);
31+
32+
STFUNC(StateWork) {
33+
switch (ev->GetTypeRewrite()) {
34+
hFunc(NHttp::TEvHttpProxy::TEvHttpIncomingResponse, Handle);
35+
cFunc(TEvents::TEvPoisonPill::EventType, PassAway);
36+
}
37+
}
38+
};
39+
40+
class TImpersonateStartPageHandler : public NActors::TActor<TImpersonateStartPageHandler> {
41+
using TBase = NActors::TActor<TImpersonateStartPageHandler>;
42+
43+
const NActors::TActorId HttpProxyId;
44+
const TOpenIdConnectSettings Settings;
45+
46+
public:
47+
TImpersonateStartPageHandler(const NActors::TActorId& httpProxyId, const TOpenIdConnectSettings& settings);
48+
void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx);
49+
50+
STFUNC(StateWork) {
51+
switch (ev->GetTypeRewrite()) {
52+
HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingRequest, Handle);
53+
cFunc(TEvents::TEvPoisonPill::EventType, PassAway);
54+
}
55+
}
56+
};
57+
58+
} // NMVP::NOIDC
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include "openid_connect.h"
2+
#include "oidc_session_create.h"
3+
#include "oidc_impersonate_stop_page_nebius.h"
4+
#include <ydb/library/actors/core/events.h>
5+
6+
namespace NMVP::NOIDC {
7+
8+
THandlerImpersonateStop::THandlerImpersonateStop(const NActors::TActorId& sender,
9+
const NHttp::THttpIncomingRequestPtr& request,
10+
const NActors::TActorId& httpProxyId,
11+
const TOpenIdConnectSettings& settings)
12+
: Sender(sender)
13+
, Request(request)
14+
, HttpProxyId(httpProxyId)
15+
, Settings(settings)
16+
{}
17+
18+
void THandlerImpersonateStop::Bootstrap() {
19+
TString impersonatedCookieName = CreateNameImpersonatedCookie(Settings.ClientId);
20+
BLOG_D("Clear impersonated cookie: (" << impersonatedCookieName << ")");
21+
22+
NHttp::THeadersBuilder responseHeaders;
23+
responseHeaders.Set("Set-Cookie", ClearSecureCookie(impersonatedCookieName));
24+
SetCORS(Request, &responseHeaders);
25+
26+
NHttp::THttpOutgoingResponsePtr httpResponse;
27+
httpResponse = Request->CreateResponse("200", "OK", responseHeaders);
28+
ReplyAndPassAway(httpResponse);
29+
}
30+
31+
void THandlerImpersonateStop::ReplyAndPassAway(NHttp::THttpOutgoingResponsePtr httpResponse) {
32+
Send(Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(httpResponse));
33+
PassAway();
34+
}
35+
36+
TImpersonateStopPageHandler::TImpersonateStopPageHandler(const NActors::TActorId& httpProxyId, const TOpenIdConnectSettings& settings)
37+
: TBase(&TImpersonateStopPageHandler::StateWork)
38+
, HttpProxyId(httpProxyId)
39+
, Settings(settings)
40+
{}
41+
42+
void TImpersonateStopPageHandler::Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx) {
43+
ctx.Register(new THandlerImpersonateStop(event->Sender, event->Get()->Request, HttpProxyId, Settings));
44+
}
45+
46+
} // NMVP::NOIDC

0 commit comments

Comments
 (0)