Skip to content

Commit

Permalink
impersonate
Browse files Browse the repository at this point in the history
  • Loading branch information
StekPerepolnen committed Nov 14, 2024
1 parent 34dcd14 commit 4c2f031
Show file tree
Hide file tree
Showing 15 changed files with 406 additions and 112 deletions.
1 change: 1 addition & 0 deletions ydb/mvp/oidc_proxy/mvp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ void TMVP::TryGetOidcOptionsFromConfig(const YAML::Node& config) {
OpenIdConnectSettings.AuthUrlPath = oidc["auth_url_path"].as<std::string>(OpenIdConnectSettings.DEFAULT_AUTH_URL_PATH);
OpenIdConnectSettings.TokenUrlPath = oidc["token_url_path"].as<std::string>(OpenIdConnectSettings.DEFAULT_TOKEN_URL_PATH);
OpenIdConnectSettings.ExchangeUrlPath = oidc["exchange_url_path"].as<std::string>(OpenIdConnectSettings.DEFAULT_EXCHANGE_URL_PATH);
OpenIdConnectSettings.ImpersonateUrlPath = oidc["impersonate_url_path"].as<std::string>(OpenIdConnectSettings.DEFAULT_IMPERSONATE_URL_PATH);
Cout << "Started processing allowed_proxy_hosts..." << Endl;
for (const std::string& host : oidc["allowed_proxy_hosts"].as<std::vector<std::string>>()) {
Cout << host << " added to allowed_proxy_hosts" << Endl;
Expand Down
24 changes: 14 additions & 10 deletions ydb/mvp/oidc_proxy/oidc_client.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "oidc_client.h"
#include "oidc_protected_page_handler.h"
#include "oidc_session_create_handler.h"
#include "oidc_impersonate_start_page_nebius.h"
#include "oidc_impersonate_stop_page_nebius.h"

namespace NMVP {
namespace NOIDC {
Expand All @@ -14,17 +16,19 @@ void InitOIDC(NActors::TActorSystem& actorSystem,
)
);

actorSystem.Send(httpProxyId, new NHttp::TEvHttpProxy::TEvRegisterHandler(
"/impersonate/start",
actorSystem.Register(new THandlerImpersonateStart(httpProxyId, settings))
)
);
if (settings.AccessServiceType == NMvp::nebius_v1) {
actorSystem.Send(httpProxyId, new NHttp::TEvHttpProxy::TEvRegisterHandler(
"/impersonate/start",
actorSystem.Register(new TImpersonateStartPageHandler(httpProxyId, settings))
)
);

actorSystem.Send(httpProxyId, new NHttp::TEvHttpProxy::TEvRegisterHandler(
"/impersonate/stop",
actorSystem.Register(new THandlerImpersonateStop(httpProxyId, settings))
)
);
actorSystem.Send(httpProxyId, new NHttp::TEvHttpProxy::TEvRegisterHandler(
"/impersonate/stop",
actorSystem.Register(new TImpersonateStopPageHandler(httpProxyId, settings))
)
);
}

actorSystem.Send(httpProxyId, new NHttp::TEvHttpProxy::TEvRegisterHandler(
"/",
Expand Down
136 changes: 70 additions & 66 deletions ydb/mvp/oidc_proxy/oidc_impersonate_start_page_nebius.cpp
Original file line number Diff line number Diff line change
@@ -1,45 +1,75 @@
#include <library/cpp/json/json_reader.h>
#include <library/cpp/string_utils/base64/base64.h>
#include <ydb/library/actors/http/http.h>
#include <ydb/library/security/util.h>
#include <ydb/mvp/core/mvp_log.h>
#include <ydb/mvp/core/mvp_tokens.h>
#include "openid_connect.h"
#include "oidc_session_create.h"
#include "oidc_settings.h"
#include "oidc_impersonate_start_page_nebius.h"

namespace NMVP {
namespace NOIDC {

THandlerImpersonateStart::THandlerImpersonateStart(const NActors::TActorId& sender,
const NHttp::THttpIncomingRequestPtr& request,
const NActors::TActorId& httpProxyId,
const TOpenIdConnectSettings& settings)
const NHttp::THttpIncomingRequestPtr& request,
const NActors::TActorId& httpProxyId,
const TOpenIdConnectSettings& settings)
: Sender(sender)
, Request(request)
, HttpProxyId(httpProxyId)
, Settings(settings)
{}

TString THandlerImpersonateStart::DecodeToken(const TStringBuf& cookie, const NActors::TActorContext& ctx) {
TString token;
try {
Base64StrictDecode(cookie, token);
} catch (std::exception& e) {
LOG_DEBUG_S(ctx, EService::MVP, "Base64Decode " << cookie << " cookie: " << e.what());
token.clear();
}
return token;
}

void THandlerImpersonateStart::Bootstrap(const NActors::TActorContext& ctx) {
LOG_DEBUG_S(ctx, EService::MVP, "Start impersonation process");
NHttp::TUrlParameters urlParameters(Request->URL);
TString serviceAccountId = urlParameters["service_accound_id"];
TString serviceAccountId = urlParameters["service_account_id"];

NHttp::THeaders headers(Request->Headers);
LOG_DEBUG_S(ctx, EService::MVP, "Start impersonation process");
NHttp::TCookies cookies(headers.Get("Cookie"));
TString sessionToken = DecodeToken(cookies, CreateNameSessionCookie(Settings.ClientId));

if (sessionToken && serviceAccountId) {
RequestImpersonatedToken(sessionToken, serviceAccountId, ctx);
} else {
TString sessionCookieName = CreateNameSessionCookie(Settings.ClientId);
TStringBuf sessionCookieValue = cookies.Get(sessionCookieName);
if (!sessionCookieValue.Empty()) {
LOG_DEBUG_S(ctx, EService::MVP, "Using session cookie (" << sessionCookieName << ": " << NKikimr::MaskTicket(sessionCookieValue) << ")");
}

TString sessionToken = DecodeToken(sessionCookieValue, ctx);

TString jsonError;
if (sessionToken.empty()) {
jsonError = "Wrong impersonate parameter: session cookie not found";
} else if (serviceAccountId.empty()) {
jsonError = "Wrong impersonate parameter: account_id not found";
}

if (jsonError) {
NHttp::THeadersBuilder responseHeaders;
responseHeaders.Set("Content-Type", "text/plain");
httpResponse = Request->CreateResponse("400", "Bad Request", responseHeaders, event->Get()->Error);
NHttp::THttpOutgoingResponsePtr httpResponse = Request->CreateResponse("400", "Bad Request", responseHeaders, jsonError);
ctx.Send(Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(httpResponse));
Die(ctx);
} else {
RequestImpersonatedToken(sessionToken, serviceAccountId, ctx);
}
}

void THandlerImpersonateStart::RequestImpersonatedToken(const TString sessionToken, const TString serviceAccountId, const NActors::TActorContext& ctx) {
void THandlerImpersonateStart::RequestImpersonatedToken(const TString& sessionToken, const TString& serviceAccountId, const NActors::TActorContext& ctx) {
LOG_DEBUG_S(ctx, EService::MVP, "Request impersonated token");
NHttp::THttpOutgoingRequestPtr httpRequest = NHttp::THttpOutgoingRequest::CreateRequestPost(Settings.GetExchangeEndpointURL());
NHttp::THttpOutgoingRequestPtr httpRequest = NHttp::THttpOutgoingRequest::CreateRequestPost(Settings.GetImpersonateEndpointURL());
httpRequest->Set<&NHttp::THttpRequest::ContentType>("application/x-www-form-urlencoded");

TMvpTokenator* tokenator = MVPAppData()->Tokenator;
Expand All @@ -48,16 +78,27 @@ void THandlerImpersonateStart::RequestImpersonatedToken(const TString sessionTok
token = tokenator->GetToken(Settings.SessionServiceTokenName);
}
httpRequest->Set("Authorization", token); // Bearer included

TStringBuilder body;
body << "grant_type=urn:ietf:params:oauth:grant-type:token-exchange"
<< "&requested_token_type=urn:ietf:params:oauth:token-type:access_token"
<< "&subject_token_type=urn:ietf:params:oauth:token-type:session_token"
<< "&subject_token=" << sessionToken;
body << "session=" << sessionToken
<< "&service_account_id=" << serviceAccountId;
httpRequest->Set<&NHttp::THttpRequest::Body>(body);

ctx.Send(HttpProxyId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest(httpRequest));
Become(&THandlerImpersonateStart::StateWork);
}

void THandlerImpersonateStart::ProcessImpersonatedToken(const TString& impersonatedToken, const NActors::TActorContext& ctx) {
TString impersonatedCookieName = CreateNameImpersonatedCookie(Settings.ClientId);
TString impersonatedCookieValue = Base64Encode(impersonatedToken);
LOG_DEBUG_S(ctx, EService::MVP, "Set impersonated cookie: (" << impersonatedCookieName << ": " << NKikimr::MaskTicket(impersonatedCookieValue) << ")");

Become(&THandlerSessionServiceCheckNebius::StateExchange);
NHttp::THeadersBuilder responseHeaders;
responseHeaders.Set("Set-Cookie", CreateSecureCookie(impersonatedCookieName, impersonatedCookieValue));
NHttp::THttpOutgoingResponsePtr httpResponse;
httpResponse = Request->CreateResponse("200", "OK", responseHeaders);
ctx.Send(Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(httpResponse));
Die(ctx);
}

void THandlerImpersonateStart::Handle(NHttp::TEvHttpProxy::TEvHttpIncomingResponse::TPtr event, const NActors::TActorContext& ctx) {
Expand All @@ -70,13 +111,13 @@ void THandlerImpersonateStart::Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRespon
NJson::TJsonValue jsonValue;
NJson::TJsonReaderConfig jsonConfig;
if (NJson::ReadJsonTree(response->Body, &jsonConfig, &jsonValue)) {
const NJson::TJsonValue* jsonAccessToken;
if (jsonValue.GetValuePointer("access_token", &jsonAccessToken)) {
TString sessionToken = jsonAccessToken->GetStringRobust();
ProcessSessionToken(sessionToken, ctx);
const NJson::TJsonValue* jsonImpersonatedToken;
if (jsonValue.GetValuePointer("impersonation", &jsonImpersonatedToken)) {
TString impersonatedToken = jsonImpersonatedToken->GetStringRobust();
ProcessImpersonatedToken(impersonatedToken, ctx);
return;
} else {
jsonError = "Wrong OIDC provider response: access_token not found";
jsonError = "Wrong OIDC provider response: impersonated token not found";
}
} else {
jsonError = "Wrong OIDC response";
Expand All @@ -98,51 +139,14 @@ void THandlerImpersonateStart::Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRespon
Die(ctx);
}

TString THandlerImpersonateStart::ChangeSameSiteFieldInSessionCookie(const TString& cookie) {
const static TStringBuf SameSiteParameter {"SameSite=Lax"};
size_t n = cookie.find(SameSiteParameter);
if (n == TString::npos) {
return cookie;
}
TStringBuilder cookieBuilder;
cookieBuilder << cookie.substr(0, n);
cookieBuilder << "SameSite=None";
cookieBuilder << cookie.substr(n + SameSiteParameter.size());
return cookieBuilder;
}

void THandlerImpersonateStart::RetryRequestToProtectedResourceAndDie(const NActors::TActorContext& ctx) {
NHttp::THeadersBuilder responseHeaders;
RetryRequestToProtectedResourceAndDie(&responseHeaders, ctx);
}

void THandlerImpersonateStart::RetryRequestToProtectedResourceAndDie(NHttp::THeadersBuilder* responseHeaders, const NActors::TActorContext& ctx) {
SetCORS(Request, responseHeaders);
responseHeaders->Set("Location", Context.GetRequestedAddress());
ctx.Send(Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(Request->CreateResponse("302", "Found", *responseHeaders)));
Die(ctx);
}
TImpersonateStartPageHandler::TImpersonateStartPageHandler(const NActors::TActorId& httpProxyId, const TOpenIdConnectSettings& settings)
: TBase(&TImpersonateStartPageHandler::StateWork)
, HttpProxyId(httpProxyId)
, Settings(settings)
{}

void THandlerImpersonateStart::SendUnknownErrorResponseAndDie(const NActors::TActorContext& ctx) {
NHttp::THeadersBuilder responseHeaders;
responseHeaders.Set("Content-Type", "text/html");
SetCORS(Request, &responseHeaders);
const static TStringBuf BAD_REQUEST_HTML_PAGE = "<html>"
"<head>"
"<title>"
"400 Bad Request"
"</title>"
"</head>"
"<body bgcolor=\"white\">"
"<center>"
"<h1>"
"Unknown error has occurred. Please open the page again"
"</h1>"
"</center>"
"</body>"
"</html>";
ctx.Send(Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(Request->CreateResponse("400", "Bad Request", responseHeaders, BAD_REQUEST_HTML_PAGE)));
Die(ctx);
void TImpersonateStartPageHandler::Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx) {
ctx.Register(new THandlerImpersonateStart(event->Sender, event->Get()->Request, HttpProxyId, Settings));
}

} // NOIDC
Expand Down
39 changes: 27 additions & 12 deletions ydb/mvp/oidc_proxy/oidc_impersonate_start_page_nebius.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,39 @@ class THandlerImpersonateStart : public NActors::TActorBootstrapped<THandlerImpe
TContext Context;

public:
TString DecodeToken(const TStringBuf& cookie, const NActors::TActorContext& ctx);
THandlerImpersonateStart(const NActors::TActorId& sender,
const NHttp::THttpIncomingRequestPtr& request,
const NActors::TActorId& httpProxyId,
const TOpenIdConnectSettings& settings);

virtual void RequestSessionToken(const TString&, const NActors::TActorContext&) = 0;
virtual void ProcessSessionToken(const TString& accessToken, const NActors::TActorContext&) = 0;
const NHttp::THttpIncomingRequestPtr& request,
const NActors::TActorId& httpProxyId,
const TOpenIdConnectSettings& settings);
void RequestImpersonatedToken(const TString&, const TString&, const NActors::TActorContext&);
void ProcessImpersonatedToken(const TString& impersonatedToken, const NActors::TActorContext& ctx);

void Bootstrap(const NActors::TActorContext& ctx);
void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingResponse::TPtr event, const NActors::TActorContext& ctx);

protected:
TString ChangeSameSiteFieldInSessionCookie(const TString& cookie);
void RetryRequestToProtectedResourceAndDie(const NActors::TActorContext& ctx);
void RetryRequestToProtectedResourceAndDie(NHttp::THeadersBuilder* responseHeaders, const NActors::TActorContext& ctx);
STFUNC(StateWork) {
switch (ev->GetTypeRewrite()) {
HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingResponse, Handle);
}
}
};

private:
void SendUnknownErrorResponseAndDie(const NActors::TActorContext& ctx);
class TImpersonateStartPageHandler : public NActors::TActor<TImpersonateStartPageHandler> {
using TBase = NActors::TActor<TImpersonateStartPageHandler>;

const NActors::TActorId HttpProxyId;
const TOpenIdConnectSettings Settings;

public:
TImpersonateStartPageHandler(const NActors::TActorId& httpProxyId, const TOpenIdConnectSettings& settings);
void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx);

STFUNC(StateWork) {
switch (ev->GetTypeRewrite()) {
HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingRequest, Handle);
}
}
};

} // NOIDC
Expand Down
26 changes: 20 additions & 6 deletions ydb/mvp/oidc_proxy/oidc_impersonate_stop_page_nebius.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,44 @@
#include "openid_connect.h"
#include "oidc_session_create.h"
#include "oidc_settings.h"
#include "oidc_impersonate_stop_page_nebius.h"

namespace NMVP {
namespace NOIDC {

THandlerImpersonateStop::THandlerSessionCreate(const NActors::TActorId& sender,
const NHttp::THttpIncomingRequestPtr& request,
const NActors::TActorId& httpProxyId,
const TOpenIdConnectSettings& settings)
THandlerImpersonateStop::THandlerImpersonateStop(const NActors::TActorId& sender,
const NHttp::THttpIncomingRequestPtr& request,
const NActors::TActorId& httpProxyId,
const TOpenIdConnectSettings& settings)
: Sender(sender)
, Request(request)
, HttpProxyId(httpProxyId)
, Settings(settings)
{}

void THandlerImpersonateStop::Bootstrap(const NActors::TActorContext& ctx) {
NHttp::THeadersBuilder responseHeaders;responseHeaders
TString impersonatedCookieName = CreateNameImpersonatedCookie(Settings.ClientId);
LOG_DEBUG_S(ctx, EService::MVP, "Clear impersonated cookie: (" << impersonatedCookieName << ")");

NHttp::THeadersBuilder responseHeaders;
SetCORS(Request, &responseHeaders);
responseHeaders.Set("Set-Cookie", CreateSecureCookie(Settings.ClientId, sessionToken));
responseHeaders.Set("Set-Cookie", ClearSecureCookie(impersonatedCookieName));

NHttp::THttpOutgoingResponsePtr httpResponse;
httpResponse = Request->CreateResponse("200", "OK", responseHeaders);
ctx.Send(Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(httpResponse));
Die(ctx);
}

TImpersonateStopPageHandler::TImpersonateStopPageHandler(const NActors::TActorId& httpProxyId, const TOpenIdConnectSettings& settings)
: TBase(&TImpersonateStopPageHandler::StateWork)
, HttpProxyId(httpProxyId)
, Settings(settings)
{}

void TImpersonateStopPageHandler::Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx) {
ctx.Register(new THandlerImpersonateStop(event->Sender, event->Get()->Request, HttpProxyId, Settings));
}

} // NOIDC
} // NMVP
23 changes: 20 additions & 3 deletions ydb/mvp/oidc_proxy/oidc_impersonate_stop_page_nebius.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,29 @@ class THandlerImpersonateStop : public NActors::TActorBootstrapped<THandlerImper

public:
THandlerImpersonateStop(const NActors::TActorId& sender,
const NHttp::THttpIncomingRequestPtr& request,
const NActors::TActorId& httpProxyId,
const TOpenIdConnectSettings& settings);
const NHttp::THttpIncomingRequestPtr& request,
const NActors::TActorId& httpProxyId,
const TOpenIdConnectSettings& settings);

void Bootstrap(const NActors::TActorContext& ctx);
};

class TImpersonateStopPageHandler : public NActors::TActor<TImpersonateStopPageHandler> {
using TBase = NActors::TActor<TImpersonateStopPageHandler>;

const NActors::TActorId HttpProxyId;
const TOpenIdConnectSettings Settings;

public:
TImpersonateStopPageHandler(const NActors::TActorId& httpProxyId, const TOpenIdConnectSettings& settings);
void Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRequest::TPtr event, const NActors::TActorContext& ctx);

STFUNC(StateWork) {
switch (ev->GetTypeRewrite()) {
HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingRequest, Handle);
}
}
};

} // NOIDC
} // NMVP
Loading

0 comments on commit 4c2f031

Please sign in to comment.