Skip to content

Commit 2dcb4bd

Browse files
Merge b7611cf into 3505562
2 parents 3505562 + b7611cf commit 2dcb4bd

File tree

3 files changed

+100
-7
lines changed

3 files changed

+100
-7
lines changed

ydb/mvp/oidc_proxy/oidc_proxy_ut.cpp

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,96 @@ Y_UNIT_TEST_SUITE(Mvp) {
467467
OidcFullAuthorizationFlow(redirectStrategy);
468468
}
469469

470+
void OidcWrongStateAuthorizationFlow(TRedirectStrategyBase& redirectStrategy) {
471+
TPortManager tp;
472+
ui16 sessionServicePort = tp.GetPort(8655);
473+
TMvpTestRuntime runtime;
474+
runtime.Initialize();
475+
476+
const TString allowedProxyHost {"ydb.viewer.page"};
477+
478+
TOpenIdConnectSettings settings {
479+
.SessionServiceEndpoint = "localhost:" + ToString(sessionServicePort),
480+
.AuthorizationServerAddress = "https://auth.cloud.yandex.ru",
481+
.ClientSecret = "0123456789abcdef",
482+
.AllowedProxyHosts = {allowedProxyHost}
483+
};
484+
485+
const NActors::TActorId edge = runtime.AllocateEdgeActor();
486+
const NActors::TActorId target = runtime.Register(new NMVP::TProtectedPageHandler(edge, settings));
487+
488+
TSessionServiceMock sessionServiceMock;
489+
sessionServiceMock.AllowedCookies.second = "allowed_session_cookie";
490+
sessionServiceMock.AllowedAccessTokens.insert("access_token_value");
491+
grpc::ServerBuilder builder;
492+
builder.AddListeningPort(settings.SessionServiceEndpoint, grpc::InsecureServerCredentials()).RegisterService(&sessionServiceMock);
493+
std::unique_ptr<grpc::Server> sessionServer(builder.BuildAndStart());
494+
495+
NHttp::THttpIncomingRequestPtr incomingRequest = new NHttp::THttpIncomingRequest();
496+
incomingRequest->Endpoint->Secure = true;
497+
498+
const TString hostProxy = "oidcproxy.yandex.net";
499+
const TString protectedPage = "/" + allowedProxyHost + "/counters";
500+
501+
EatWholeString(incomingRequest, redirectStrategy.CreateRequest("GET " + protectedPage + " HTTP/1.1\r\n"
502+
"Host: " + hostProxy + "\r\n"
503+
"Cookie: yc_session=invalid_cookie\r\n"
504+
"Referer: https://" + hostProxy + protectedPage + "\r\n"));
505+
runtime.Send(new IEventHandle(target, edge, new NHttp::TEvHttpProxy::TEvHttpIncomingRequest(incomingRequest)));
506+
507+
TAutoPtr<IEventHandle> handle;
508+
NHttp::TEvHttpProxy::TEvHttpOutgoingResponse* outgoingResponseEv = runtime.GrabEdgeEvent<NHttp::TEvHttpProxy::TEvHttpOutgoingResponse>(handle);
509+
redirectStrategy.CheckRedirectStatus(outgoingResponseEv);
510+
TString location = redirectStrategy.GetRedirectUrl(outgoingResponseEv);
511+
UNIT_ASSERT_STRING_CONTAINS(location, "https://auth.cloud.yandex.ru/oauth/authorize");
512+
UNIT_ASSERT_STRING_CONTAINS(location, "response_type=code");
513+
UNIT_ASSERT_STRING_CONTAINS(location, "scope=openid");
514+
UNIT_ASSERT_STRING_CONTAINS(location, "client_id=" + TOpenIdConnectSettings::CLIENT_ID);
515+
UNIT_ASSERT_STRING_CONTAINS(location, "redirect_uri=https://" + hostProxy + "/auth/callback");
516+
517+
NHttp::TUrlParameters urlParameters(location);
518+
const TString state = urlParameters["state"];
519+
520+
const NHttp::THeaders headers(outgoingResponseEv->Response->Headers);
521+
UNIT_ASSERT(headers.Has("Set-Cookie"));
522+
TStringBuf setCookie = headers.Get("Set-Cookie");
523+
UNIT_ASSERT_STRING_CONTAINS(setCookie, CreateNameYdbOidcCookie(settings.ClientSecret, state));
524+
redirectStrategy.CheckSpecificHeaders(headers);
525+
526+
const NActors::TActorId sessionCreator = runtime.Register(new NMVP::TSessionCreator(edge, settings));
527+
incomingRequest = new NHttp::THttpIncomingRequest();
528+
TStringBuilder request;
529+
request << "GET /auth/callback?code=code_template&state=" << "wrong_state!" << " HTTP/1.1\r\n";
530+
request << "Host: " + hostProxy + "\r\n";
531+
request << "Cookie: " << setCookie.NextTok(";") << "\r\n";
532+
EatWholeString(incomingRequest, redirectStrategy.CreateRequest(request));
533+
incomingRequest->Endpoint->Secure = true;
534+
runtime.Send(new IEventHandle(sessionCreator, edge, new NHttp::TEvHttpProxy::TEvHttpIncomingRequest(incomingRequest)));
535+
536+
outgoingResponseEv = runtime.GrabEdgeEvent<NHttp::TEvHttpProxy::TEvHttpOutgoingResponse>(handle);
537+
UNIT_ASSERT_STRINGS_EQUAL(outgoingResponseEv->Response->Status, "302");
538+
{
539+
const NHttp::THeaders headers(outgoingResponseEv->Response->Headers);
540+
UNIT_ASSERT(headers.Has("Location"));
541+
TString location = TString(headers.Get("Location"));
542+
UNIT_ASSERT_STRING_CONTAINS(location, "https://auth.cloud.yandex.ru/oauth/authorize");
543+
UNIT_ASSERT_STRING_CONTAINS(location, "response_type=code");
544+
UNIT_ASSERT_STRING_CONTAINS(location, "scope=openid");
545+
UNIT_ASSERT_STRING_CONTAINS(location, "client_id=" + TOpenIdConnectSettings::CLIENT_ID);
546+
UNIT_ASSERT_STRING_CONTAINS(location, "redirect_uri=https://" + hostProxy + "/auth/callback");
547+
}
548+
}
549+
550+
Y_UNIT_TEST(OpenIdConnectotWrongStateAuthorizationFlow) {
551+
TRedirectStrategy redirectStrategy;
552+
OidcWrongStateAuthorizationFlow(redirectStrategy);
553+
}
554+
555+
Y_UNIT_TEST(OpenIdConnectotWrongStateAuthorizationFlowAjax) {
556+
TAjaxRedirectStrategy redirectStrategy;
557+
OidcWrongStateAuthorizationFlow(redirectStrategy);
558+
}
559+
470560
Y_UNIT_TEST(OpenIdConnectSessionServiceCreateAuthorizationFail) {
471561
TPortManager tp;
472562
ui16 sessionServicePort = tp.GetPort(8655);

ydb/mvp/oidc_proxy/oidc_session_create.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ class THandlerSessionCreate : public NActors::TActorBootstrapped<THandlerSession
142142
NHttp::THeaders headers(Request->Headers);
143143
NHttp::TCookies cookies(headers.Get("cookie"));
144144

145-
if (!code.Empty() && IsStateValid(state, cookies, ctx)) {
145+
if (IsStateValid(state, cookies, ctx) && !code.Empty()) {
146146
NHttp::THttpOutgoingRequestPtr httpRequest = NHttp::THttpOutgoingRequest::CreateRequestPost(Settings.AuthorizationServerAddress + "/oauth/token");
147147
httpRequest->Set<&NHttp::THttpRequest::ContentType>("application/x-www-form-urlencoded");
148148
httpRequest->Set("Authorization", "Basic " + Settings.GetAuthorizationString());
@@ -151,8 +151,7 @@ class THandlerSessionCreate : public NActors::TActorBootstrapped<THandlerSession
151151
httpRequest->Set<&NHttp::THttpRequest::Body>(body);
152152
ctx.Send(HttpProxyId, new NHttp::TEvHttpProxy::TEvHttpOutgoingRequest(httpRequest));
153153
} else {
154-
ResponseHeaders.Set("Content-Type", "text/plain");
155-
NHttp::THttpOutgoingResponsePtr response = Request->CreateResponse("400", "Bad Request", ResponseHeaders, "Parameters state and code are invalid");
154+
NHttp::THttpOutgoingResponsePtr response = GetHttpOutgoingResponsePtr(TStringBuf(), Request, Settings, ResponseHeaders, IsAjaxRequest);
156155
ctx.Send(Sender, new NHttp::TEvHttpProxy::TEvHttpOutgoingResponse(response));
157156
TBase::Die(ctx);
158157
return;

ydb/mvp/oidc_proxy/openid_connect.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,14 @@ TString CreateRedirectUrl(const TRedirectUrlParameters& parameters) {
3030
TStringBuilder locationHeaderValue;
3131
TStringBuf authUrl = "/oauth/authorize";
3232
const auto& eventDetails = parameters.SessionServerCheckDetails;
33-
size_t posAuthUrl = eventDetails.find(authUrl);
34-
if (posAuthUrl != TStringBuf::npos) {
35-
size_t pos = eventDetails.rfind("https://", posAuthUrl);
36-
locationHeaderValue << eventDetails.substr(pos, posAuthUrl - pos);
33+
if (eventDetails) {
34+
size_t posAuthUrl = eventDetails.find(authUrl);
35+
if (posAuthUrl != TStringBuf::npos) {
36+
size_t pos = eventDetails.rfind("https://", posAuthUrl);
37+
locationHeaderValue << eventDetails.substr(pos, posAuthUrl - pos);
38+
} else {
39+
locationHeaderValue << parameters.OidcSettings.AuthorizationServerAddress;
40+
}
3741
} else {
3842
locationHeaderValue << parameters.OidcSettings.AuthorizationServerAddress;
3943
}

0 commit comments

Comments
 (0)