diff --git a/ydb/mvp/oidc_proxy/oidc_impersonate_start_page_nebius.cpp b/ydb/mvp/oidc_proxy/oidc_impersonate_start_page_nebius.cpp index d23265864d12..3a7af852cbe6 100644 --- a/ydb/mvp/oidc_proxy/oidc_impersonate_start_page_nebius.cpp +++ b/ydb/mvp/oidc_proxy/oidc_impersonate_start_page_nebius.cpp @@ -66,13 +66,23 @@ void THandlerImpersonateStart::RequestImpersonatedToken(TString& sessionToken, T Become(&THandlerImpersonateStart::StateWork); } -void THandlerImpersonateStart::ProcessImpersonatedToken(const TString& impersonatedToken) { +void THandlerImpersonateStart::ProcessImpersonatedToken(const NJson::TJsonValue& jsonValue) { + const NJson::TJsonValue* jsonImpersonatedToken; + const NJson::TJsonValue* jsonExpiresIn; + if (!jsonValue.GetValuePointer("impersonation", &jsonImpersonatedToken)) { + return ReplyBadRequestAndPassAway("Wrong OIDC provider response: impersonation not found"); + } + if (!jsonValue.GetValuePointer("expires_in", &jsonExpiresIn)) { + return ReplyBadRequestAndPassAway("Wrong OIDC provider response: expires_in not found"); + } + TString impersonatedToken = jsonImpersonatedToken->GetStringRobust(); + long long expiresIn = jsonExpiresIn->GetIntegerRobust(); TString impersonatedCookieName = CreateNameImpersonatedCookie(Settings.ClientId); TString impersonatedCookieValue = Base64Encode(impersonatedToken); BLOG_D("Set impersonated cookie: (" << impersonatedCookieName << ": " << NKikimr::MaskTicket(impersonatedCookieValue) << ")"); NHttp::THeadersBuilder responseHeaders; - responseHeaders.Set("Set-Cookie", CreateSecureCookie(impersonatedCookieName, impersonatedCookieValue)); + responseHeaders.Set("Set-Cookie", CreateSecureCookie(impersonatedCookieName, impersonatedCookieValue, expiresIn)); SetCORS(Request, &responseHeaders); ReplyAndPassAway(Request->CreateResponse("200", "OK", responseHeaders)); } @@ -82,25 +92,12 @@ void THandlerImpersonateStart::Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRespon NHttp::THttpIncomingResponsePtr response = std::move(event->Get()->Response); BLOG_D("Incoming response from authorization server: " << response->Status); if (response->Status == "200") { - TStringBuf errorMessage; NJson::TJsonValue jsonValue; NJson::TJsonReaderConfig jsonConfig; if (NJson::ReadJsonTree(response->Body, &jsonConfig, &jsonValue)) { - const NJson::TJsonValue* jsonImpersonatedToken; - if (jsonValue.GetValuePointer("impersonation", &jsonImpersonatedToken)) { - TString impersonatedToken = jsonImpersonatedToken->GetStringRobust(); - ProcessImpersonatedToken(impersonatedToken); - return; - } else { - errorMessage = "Wrong OIDC provider response: impersonated token not found"; - } - } else { - errorMessage = "Wrong OIDC response"; + return ProcessImpersonatedToken(jsonValue); } - NHttp::THeadersBuilder responseHeaders; - responseHeaders.Set("Content-Type", "text/plain"); - SetCORS(Request, &responseHeaders); - return ReplyAndPassAway(Request->CreateResponse("400", "Bad Request", responseHeaders, errorMessage)); + return ReplyBadRequestAndPassAway("Wrong OIDC response"); } else { NHttp::THeadersBuilder responseHeaders; NHttp::THeaders headers(response->Headers); @@ -110,12 +107,9 @@ void THandlerImpersonateStart::Handle(NHttp::TEvHttpProxy::TEvHttpIncomingRespon SetCORS(Request, &responseHeaders); return ReplyAndPassAway(Request->CreateResponse(response->Status, response->Message, responseHeaders, response->Body)); } - } else { - NHttp::THeadersBuilder responseHeaders; - responseHeaders.Set("Content-Type", "text/plain"); - SetCORS(Request, &responseHeaders); - return ReplyAndPassAway(Request->CreateResponse("400", "Bad Request", responseHeaders, event->Get()->Error)); } + + ReplyBadRequestAndPassAway(event->Get()->Error); } void THandlerImpersonateStart::ReplyAndPassAway(NHttp::THttpOutgoingResponsePtr httpResponse) { diff --git a/ydb/mvp/oidc_proxy/oidc_impersonate_start_page_nebius.h b/ydb/mvp/oidc_proxy/oidc_impersonate_start_page_nebius.h index 2c9c904d5a26..ee8504269c7e 100644 --- a/ydb/mvp/oidc_proxy/oidc_impersonate_start_page_nebius.h +++ b/ydb/mvp/oidc_proxy/oidc_impersonate_start_page_nebius.h @@ -23,7 +23,7 @@ class THandlerImpersonateStart : public NActors::TActorBootstrappedRequest->URL, "/oauth2/impersonation/impersonate"); UNIT_ASSERT_EQUAL(outgoingRequestEv->Request->Secure, true); NHttp::THttpIncomingResponsePtr incomingResponse = new NHttp::THttpIncomingResponse(outgoingRequestEv->Request); - TString okResponseBody {"{\"impersonation\": \"impersonation_token\"}"}; + TString okResponseBody {"{\"impersonation\": \"impersonation_token\", \"expires_in\": 43200}"}; EatWholeString(incomingResponse, "HTTP/1.1 200 OK\r\n" "Connection: close\r\n" "Content-Type: text/html\r\n" @@ -1182,7 +1182,7 @@ Y_UNIT_TEST_SUITE(Mvp) { const NHttp::THeaders impersonatePageHeaders(outgoingResponseEv->Response->Headers); UNIT_ASSERT(impersonatePageHeaders.Has("Set-Cookie")); TStringBuf impersonatedCookie = impersonatePageHeaders.Get("Set-Cookie"); - TString expectedCookie = CreateSecureCookie(CreateNameImpersonatedCookie(settings.ClientId), Base64Encode("impersonation_token")); + TString expectedCookie = CreateSecureCookie(CreateNameImpersonatedCookie(settings.ClientId), Base64Encode("impersonation_token"), 43200); UNIT_ASSERT_STRINGS_EQUAL(impersonatedCookie, expectedCookie); } diff --git a/ydb/mvp/oidc_proxy/oidc_session_create.cpp b/ydb/mvp/oidc_proxy/oidc_session_create.cpp index bb3afda3dc59..5eddde39a52c 100644 --- a/ydb/mvp/oidc_proxy/oidc_session_create.cpp +++ b/ydb/mvp/oidc_proxy/oidc_session_create.cpp @@ -58,40 +58,32 @@ void THandlerSessionCreate::Bootstrap() { } -void THandlerSessionCreate::Handle(NHttp::TEvHttpProxy::TEvHttpIncomingResponse::TPtr event, const NActors::TActorContext& ctx) { +void THandlerSessionCreate::ReplyBadRequestAndPassAway(TString errorMessage) { + NHttp::THeadersBuilder responseHeaders; + SetCORS(Request, &responseHeaders); + responseHeaders.Set("Content-Type", "text/plain"); + return ReplyAndPassAway(Request->CreateResponse("400", "Bad Request", responseHeaders, errorMessage)); +} + +void THandlerSessionCreate::Handle(NHttp::TEvHttpProxy::TEvHttpIncomingResponse::TPtr event) { if (event->Get()->Error.empty() && event->Get()->Response) { NHttp::THttpIncomingResponsePtr response = std::move(event->Get()->Response); BLOG_D("Incoming response from authorization server: " << response->Status); if (response->Status == "200") { - TStringBuf errorMessage; 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(); - return ProcessSessionToken(sessionToken, ctx); - } else { - errorMessage = "Wrong OIDC provider response: access_token not found"; - } - } else { - errorMessage = "Wrong OIDC response"; + return ProcessSessionToken(jsonValue); } - NHttp::THeadersBuilder responseHeaders; - SetCORS(Request, &responseHeaders); - responseHeaders.Set("Content-Type", "text/plain"); - return ReplyAndPassAway(Request->CreateResponse("400", "Bad Request", responseHeaders, errorMessage)); + return ReplyBadRequestAndPassAway("Wrong OIDC response"); } else { NHttp::THeadersBuilder responseHeaders; responseHeaders.Parse(response->Headers); return ReplyAndPassAway(Request->CreateResponse(response->Status, response->Message, responseHeaders, response->Body)); } - } else { - NHttp::THeadersBuilder responseHeaders; - SetCORS(Request, &responseHeaders); - responseHeaders.Set("Content-Type", "text/plain"); - return ReplyAndPassAway(Request->CreateResponse("400", "Bad Request", responseHeaders, event->Get()->Error)); } + + return ReplyBadRequestAndPassAway(event->Get()->Error); } TString THandlerSessionCreate::ChangeSameSiteFieldInSessionCookie(const TString& cookie) { diff --git a/ydb/mvp/oidc_proxy/oidc_session_create.h b/ydb/mvp/oidc_proxy/oidc_session_create.h index b45f96a36ccf..d1c2f2c150a9 100644 --- a/ydb/mvp/oidc_proxy/oidc_session_create.h +++ b/ydb/mvp/oidc_proxy/oidc_session_create.h @@ -29,16 +29,17 @@ class THandlerSessionCreate : public NActors::TActorBootstrappedGetStringRobust(); + long long expiresIn = jsonExpiresIn->GetIntegerRobust(); TString sessionCookieName = CreateNameSessionCookie(Settings.ClientId); TString sessionCookieValue = Base64Encode(sessionToken); BLOG_D("Set session cookie: (" << sessionCookieName << ": " << NKikimr::MaskTicket(sessionCookieValue) << ")"); NHttp::THeadersBuilder responseHeaders; SetCORS(Request, &responseHeaders); - responseHeaders.Set("Set-Cookie", CreateSecureCookie(sessionCookieName, sessionCookieValue)); + responseHeaders.Set("Set-Cookie", CreateSecureCookie(sessionCookieName, sessionCookieValue, expiresIn)); responseHeaders.Set("Location", Context.GetRequestedAddress()); ReplyAndPassAway(Request->CreateResponse("302", "Cookie set", responseHeaders)); } diff --git a/ydb/mvp/oidc_proxy/oidc_session_create_nebius.h b/ydb/mvp/oidc_proxy/oidc_session_create_nebius.h index 7dcd8a1197b3..260b3da9c75f 100644 --- a/ydb/mvp/oidc_proxy/oidc_session_create_nebius.h +++ b/ydb/mvp/oidc_proxy/oidc_session_create_nebius.h @@ -15,12 +15,12 @@ class THandlerSessionCreateNebius : public THandlerSessionCreate { const TOpenIdConnectSettings& settings); void RequestSessionToken(const TString& code) override; - void ProcessSessionToken(const TString& sessionToken, const NActors::TActorContext& ctx) override; + void ProcessSessionToken(const NJson::TJsonValue& jsonValue) override; private: STFUNC(StateWork) { switch (ev->GetTypeRewrite()) { - HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingResponse, Handle); + hFunc(NHttp::TEvHttpProxy::TEvHttpIncomingResponse, Handle); } } }; diff --git a/ydb/mvp/oidc_proxy/oidc_session_create_yandex.cpp b/ydb/mvp/oidc_proxy/oidc_session_create_yandex.cpp index 6a3c45420ddf..ae4a68961944 100644 --- a/ydb/mvp/oidc_proxy/oidc_session_create_yandex.cpp +++ b/ydb/mvp/oidc_proxy/oidc_session_create_yandex.cpp @@ -9,6 +9,8 @@ namespace NMVP { namespace NOIDC { +using namespace NActors; + THandlerSessionCreateYandex::THandlerSessionCreateYandex(const NActors::TActorId& sender, const NHttp::THttpIncomingRequestPtr& request, const NActors::TActorId& httpProxyId, @@ -30,7 +32,12 @@ void THandlerSessionCreateYandex::RequestSessionToken(const TString& code) { Become(&THandlerSessionCreateYandex::StateWork); } -void THandlerSessionCreateYandex::ProcessSessionToken(const TString& sessionToken, const NActors::TActorContext& ctx) { +void THandlerSessionCreateYandex::ProcessSessionToken(const NJson::TJsonValue& jsonValue) { + const NJson::TJsonValue* jsonAccessToken, jsonExpiresIn; + if (!jsonValue.GetValuePointer("access_token", &jsonAccessToken)) { + return ReplyBadRequestAndPassAway("Wrong OIDC provider response: access_token not found"); + } + TString sessionToken = jsonAccessToken->GetStringRobust(); std::unique_ptr> connection = CreateGRpcServiceConnection(Settings.SessionServiceEndpoint); yandex::cloud::priv::oauth::v1::CreateSessionRequest requestCreate; @@ -45,8 +52,8 @@ void THandlerSessionCreateYandex::ProcessSessionToken(const TString& sessionToke SetHeader(meta, "authorization", token); meta.Timeout = TDuration::Seconds(10); - NActors::TActorSystem* actorSystem = ctx.ActorSystem(); - NActors::TActorId actorId = ctx.SelfID; + NActors::TActorSystem* actorSystem = TlsActivationContext->ActorSystem(); + NActors::TActorId actorId = SelfId(); NYdbGrpc::TResponseCallback responseCb = [actorId, actorSystem](NYdbGrpc::TGrpcStatus&& status, yandex::cloud::priv::oauth::v1::CreateSessionResponse&& response) -> void { if (status.Ok()) { diff --git a/ydb/mvp/oidc_proxy/oidc_session_create_yandex.h b/ydb/mvp/oidc_proxy/oidc_session_create_yandex.h index 8114c29f78be..dbd8b83d7f3a 100644 --- a/ydb/mvp/oidc_proxy/oidc_session_create_yandex.h +++ b/ydb/mvp/oidc_proxy/oidc_session_create_yandex.h @@ -17,14 +17,14 @@ class THandlerSessionCreateYandex : public THandlerSessionCreate { const TOpenIdConnectSettings& settings); void RequestSessionToken(const TString& code) override; - void ProcessSessionToken(const TString& sessionToken, const NActors::TActorContext& ctx) override; + void ProcessSessionToken(const NJson::TJsonValue& jsonValue) override; void HandleCreateSession(TEvPrivate::TEvCreateSessionResponse::TPtr event); void HandleError(TEvPrivate::TEvErrorResponse::TPtr event); private: STFUNC(StateWork) { switch (ev->GetTypeRewrite()) { - HFunc(NHttp::TEvHttpProxy::TEvHttpIncomingResponse, Handle); + hFunc(NHttp::TEvHttpProxy::TEvHttpIncomingResponse, Handle); hFunc(TEvPrivate::TEvCreateSessionResponse, HandleCreateSession); hFunc(TEvPrivate::TEvErrorResponse, HandleError); } diff --git a/ydb/mvp/oidc_proxy/openid_connect.cpp b/ydb/mvp/oidc_proxy/openid_connect.cpp index 18d5578f67a4..82f34ef06262 100644 --- a/ydb/mvp/oidc_proxy/openid_connect.cpp +++ b/ydb/mvp/oidc_proxy/openid_connect.cpp @@ -121,10 +121,11 @@ const TString& GetAuthCallbackUrl() { return callbackUrl; } -TString CreateSecureCookie(const TString& name, const TString& value) { +TString CreateSecureCookie(const TString& name, const TString& value, const ui32 expiredSeconds) { TStringBuilder cookieBuilder; cookieBuilder << name << "=" << value - << "; Path=/; Secure; HttpOnly; SameSite=None; Partitioned"; + << "; Path=/; Secure; HttpOnly; SameSite=None; Partitioned" + << "; Max-Age=" << expiredSeconds; return cookieBuilder; } diff --git a/ydb/mvp/oidc_proxy/openid_connect.h b/ydb/mvp/oidc_proxy/openid_connect.h index 76b639115098..c0eacf316b95 100644 --- a/ydb/mvp/oidc_proxy/openid_connect.h +++ b/ydb/mvp/oidc_proxy/openid_connect.h @@ -45,7 +45,7 @@ TString CreateNameYdbOidcCookie(TStringBuf key, TStringBuf state); TString CreateNameSessionCookie(TStringBuf key); TString CreateNameImpersonatedCookie(TStringBuf key); const TString& GetAuthCallbackUrl(); -TString CreateSecureCookie(const TString& name, const TString& value); +TString CreateSecureCookie(const TString& name, const TString& value, const ui32 expiredSeconds); TString ClearSecureCookie(const TString& name); void SetCORS(const NHttp::THttpIncomingRequestPtr& request, NHttp::THeadersBuilder* const headers); TRestoreOidcContextResult RestoreOidcContext(const NHttp::TCookies& cookies, const TString& key);