diff options
author | Andrei Rykov <[email protected]> | 2025-07-28 14:07:41 +0200 |
---|---|---|
committer | GitHub <[email protected]> | 2025-07-28 14:07:41 +0200 |
commit | 5183c237ccdf995146da1705bebf034a64b1d21f (patch) | |
tree | 1132f66da3631ab7be156e63a3300afd42bc90f8 | |
parent | 2396609e2d90829dcc6e88fcfc099becd1309bc8 (diff) |
Add X-Forwarded-For http header to keep source address (#21649)
-rw-r--r-- | ydb/mvp/oidc_proxy/oidc_proxy_ut.cpp | 11 | ||||
-rw-r--r-- | ydb/mvp/oidc_proxy/openid_connect.cpp | 47 | ||||
-rw-r--r-- | ydb/mvp/oidc_proxy/openid_connect.h | 2 |
3 files changed, 59 insertions, 1 deletions
diff --git a/ydb/mvp/oidc_proxy/oidc_proxy_ut.cpp b/ydb/mvp/oidc_proxy/oidc_proxy_ut.cpp index 2adb4571d35..1034f29a30c 100644 --- a/ydb/mvp/oidc_proxy/oidc_proxy_ut.cpp +++ b/ydb/mvp/oidc_proxy/oidc_proxy_ut.cpp @@ -1747,4 +1747,15 @@ Y_UNIT_TEST_SUITE(Mvp) { UNIT_ASSERT(!json.Has(EXTENDED_INFO)); UNIT_ASSERT(!json.Has(EXTENDED_ERRORS)); } + + Y_UNIT_TEST(GetAddressWithoutPort) { + UNIT_ASSERT_VALUES_EQUAL(GetAddressWithoutPort("[2001:db8::1]:8080"), "2001:db8::1"); + UNIT_ASSERT_VALUES_EQUAL(GetAddressWithoutPort("2001:db8::1:8080"), "2001:db8::1:8080"); // raw IPv6 + UNIT_ASSERT_VALUES_EQUAL(GetAddressWithoutPort("192.168.1.1:8080"), "192.168.1.1"); + UNIT_ASSERT_VALUES_EQUAL(GetAddressWithoutPort("192.168.1.1"), "192.168.1.1"); + UNIT_ASSERT_VALUES_EQUAL(GetAddressWithoutPort("localhost:9090"), "localhost"); + UNIT_ASSERT_VALUES_EQUAL(GetAddressWithoutPort("localhost"), "localhost"); + UNIT_ASSERT_VALUES_EQUAL(GetAddressWithoutPort("some.domain.name:1234"), "some.domain.name"); + UNIT_ASSERT_VALUES_EQUAL(GetAddressWithoutPort("some.domain.name"), "some.domain.name"); + } } diff --git a/ydb/mvp/oidc_proxy/openid_connect.cpp b/ydb/mvp/oidc_proxy/openid_connect.cpp index 4bed3969958..d32a574b976 100644 --- a/ydb/mvp/oidc_proxy/openid_connect.cpp +++ b/ydb/mvp/oidc_proxy/openid_connect.cpp @@ -262,9 +262,51 @@ TStringBuf GetCookie(const NHttp::TCookies& cookies, const TString& cookieName) return cookieValue; } +TString GetAddressWithoutPort(const TString& address) { + // IPv6 with brackets: [addr]:port -> addr + if (address.StartsWith('[')) { + auto end = address.find(']'); + if (end != TString::npos) { + return address.substr(1, end - 1); + } + } + + // IPv6 without brackets - leave unchanged just in case + if (std::count(address.begin(), address.end(), ':') > 1) { + return address; + } + + // IPv4 with port: addr:port → addr + auto pos = address.rfind(':'); + if (pos != TString::npos) { + return address.substr(0, pos); + } + + return address; +} + +// Append request address to X-Forwarded-For header +// Useful for logging and audit +TString MakeXForwardedFor(const TProxiedRequestParams& params) { + NHttp::THeaders headers(params.Request->Headers); + + TStringBuilder forwarded; + forwarded << headers.Get(X_FORWARDED_FOR_HEADER); + if (params.Request->Address) { + auto address = GetAddressWithoutPort(params.Request->Address->ToString()); + if (!address.empty()) { + if (!forwarded.empty()) { + forwarded << ", "; + } + forwarded << address; + } + } + return std::move(forwarded); +} + NHttp::THttpOutgoingRequestPtr CreateProxiedRequest(const TProxiedRequestParams& params) { auto outRequest = NHttp::THttpOutgoingRequest::CreateRequest(params.Request->Method, params.ProtectedPage.Url); - NHttp::THeadersBuilder headers(params.Request->Headers); + NHttp::THeaders headers(params.Request->Headers); for (const auto& header : params.Settings.REQUEST_HEADERS_WHITE_LIST) { if (headers.Has(header)) { outRequest->Set(header, headers.Get(header)); @@ -275,6 +317,9 @@ NHttp::THttpOutgoingRequestPtr CreateProxiedRequest(const TProxiedRequestParams& if (!params.AuthHeader.empty()) { outRequest->Set(AUTHORIZATION_HEADER, params.AuthHeader); } + + outRequest->Set(X_FORWARDED_FOR_HEADER, MakeXForwardedFor(params)); + if (params.Request->HaveBody()) { outRequest->SetBody(params.Request->Body); } diff --git a/ydb/mvp/oidc_proxy/openid_connect.h b/ydb/mvp/oidc_proxy/openid_connect.h index 4250745ba14..a4b3f958832 100644 --- a/ydb/mvp/oidc_proxy/openid_connect.h +++ b/ydb/mvp/oidc_proxy/openid_connect.h @@ -20,6 +20,7 @@ struct TOpenIdConnectSettings; constexpr TStringBuf IAM_TOKEN_SCHEME = "Bearer "; constexpr TStringBuf IAM_TOKEN_SCHEME_LOWER = "bearer "; constexpr TStringBuf AUTHORIZATION_HEADER = "Authorization"; +constexpr TStringBuf X_FORWARDED_FOR_HEADER = "X-Forwarded-For"; constexpr TStringBuf LOCATION_HEADER = "Location"; constexpr TStringBuf USER_SID = "UserSID"; @@ -66,6 +67,7 @@ TRestoreOidcContextResult RestoreOidcContext(const NHttp::TCookies& cookies, con TCheckStateResult CheckState(const TString& state, const TString& key); TString DecodeToken(const TStringBuf& cookie); TStringBuf GetCookie(const NHttp::TCookies& cookies, const TString& cookieName); +TString GetAddressWithoutPort(const TString& address); struct TProxiedRequestParams { |