Skip to content

Commit 79aa281

Browse files
oidc proxy AuthorizationServer redirect on wrong state (#4641)
1 parent b508586 commit 79aa281

File tree

2 files changed

+58
-3
lines changed

2 files changed

+58
-3
lines changed

ydb/mvp/oidc_proxy/oidc_proxy_ut.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,62 @@ 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+
TOpenIdConnectSettings settings {
477+
.SessionServiceEndpoint = "localhost:" + ToString(sessionServicePort),
478+
.AuthorizationServerAddress = "https://auth.cloud.yandex.ru",
479+
.ClientSecret = "0123456789abcdef"
480+
};
481+
482+
const NActors::TActorId edge = runtime.AllocateEdgeActor();
483+
484+
TSessionServiceMock sessionServiceMock;
485+
sessionServiceMock.AllowedAccessTokens.insert("valid_access_token");
486+
grpc::ServerBuilder builder;
487+
builder.AddListeningPort(settings.SessionServiceEndpoint, grpc::InsecureServerCredentials()).RegisterService(&sessionServiceMock);
488+
std::unique_ptr<grpc::Server> sessionServer(builder.BuildAndStart());
489+
490+
const NActors::TActorId sessionCreator = runtime.Register(new NMVP::TSessionCreator(edge, settings));
491+
const TString state = "test_state";
492+
const TString wrongState = "wrong_state";
493+
const TString hostProxy = "oidcproxy.yandex.net";
494+
TStringBuilder request;
495+
request << "GET /auth/callback?code=code_template&state=" << state << " HTTP/1.1\r\n";
496+
request << "Host: " + hostProxy + "\r\n";
497+
request << "Cookie: " << CreateNameYdbOidcCookie(settings.ClientSecret, wrongState) << "=" << GenerateCookie(wrongState, "/requested/page", settings.ClientSecret, redirectStrategy.IsAjaxRequest()) << "\r\n";
498+
NHttp::THttpIncomingRequestPtr incomingRequest = new NHttp::THttpIncomingRequest();
499+
EatWholeString(incomingRequest, redirectStrategy.CreateRequest(request));
500+
incomingRequest->Endpoint->Secure = true;
501+
runtime.Send(new IEventHandle(sessionCreator, edge, new NHttp::TEvHttpProxy::TEvHttpIncomingRequest(incomingRequest)));
502+
503+
TAutoPtr<IEventHandle> handle;
504+
NHttp::TEvHttpProxy::TEvHttpOutgoingResponse* outgoingResponseEv = runtime.GrabEdgeEvent<NHttp::TEvHttpProxy::TEvHttpOutgoingResponse>(handle);
505+
UNIT_ASSERT_STRINGS_EQUAL(outgoingResponseEv->Response->Status, "302");
506+
const NHttp::THeaders headers(outgoingResponseEv->Response->Headers);
507+
UNIT_ASSERT(headers.Has("Location"));
508+
TString location = TString(headers.Get("Location"));
509+
UNIT_ASSERT_STRING_CONTAINS(location, "https://auth.cloud.yandex.ru/oauth/authorize");
510+
UNIT_ASSERT_STRING_CONTAINS(location, "response_type=code");
511+
UNIT_ASSERT_STRING_CONTAINS(location, "scope=openid");
512+
UNIT_ASSERT_STRING_CONTAINS(location, "client_id=" + TOpenIdConnectSettings::CLIENT_ID);
513+
UNIT_ASSERT_STRING_CONTAINS(location, "redirect_uri=https://" + hostProxy + "/auth/callback");
514+
}
515+
516+
Y_UNIT_TEST(OpenIdConnectotWrongStateAuthorizationFlow) {
517+
TRedirectStrategy redirectStrategy;
518+
OidcWrongStateAuthorizationFlow(redirectStrategy);
519+
}
520+
521+
Y_UNIT_TEST(OpenIdConnectotWrongStateAuthorizationFlowAjax) {
522+
TAjaxRedirectStrategy redirectStrategy;
523+
OidcWrongStateAuthorizationFlow(redirectStrategy);
524+
}
525+
470526
Y_UNIT_TEST(OpenIdConnectSessionServiceCreateAuthorizationFail) {
471527
TPortManager tp;
472528
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;

0 commit comments

Comments
 (0)