Skip to content

Commit c795117

Browse files
Merge 94ddfa3 into 0a30799
2 parents 0a30799 + 94ddfa3 commit c795117

15 files changed

+697
-20
lines changed

ydb/mvp/oidc_proxy/mvp.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ void TMVP::TryGetOidcOptionsFromConfig(const YAML::Node& config) {
233233
OpenIdConnectSettings.AuthUrlPath = oidc["auth_url_path"].as<std::string>(OpenIdConnectSettings.DEFAULT_AUTH_URL_PATH);
234234
OpenIdConnectSettings.TokenUrlPath = oidc["token_url_path"].as<std::string>(OpenIdConnectSettings.DEFAULT_TOKEN_URL_PATH);
235235
OpenIdConnectSettings.ExchangeUrlPath = oidc["exchange_url_path"].as<std::string>(OpenIdConnectSettings.DEFAULT_EXCHANGE_URL_PATH);
236+
OpenIdConnectSettings.ImpersonateUrlPath = oidc["impersonate_url_path"].as<std::string>(OpenIdConnectSettings.DEFAULT_IMPERSONATE_URL_PATH);
236237
Cout << "Started processing allowed_proxy_hosts..." << Endl;
237238
for (const std::string& host : oidc["allowed_proxy_hosts"].as<std::vector<std::string>>()) {
238239
Cout << host << " added to allowed_proxy_hosts" << Endl;

ydb/mvp/oidc_proxy/oidc_client.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
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

57
namespace NMVP {
68
namespace NOIDC {
@@ -14,6 +16,20 @@ void InitOIDC(NActors::TActorSystem& actorSystem,
1416
)
1517
);
1618

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

0 commit comments

Comments
 (0)