@@ -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 );
0 commit comments