summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrei Rykov <[email protected]>2025-07-28 14:07:41 +0200
committerGitHub <[email protected]>2025-07-28 14:07:41 +0200
commit5183c237ccdf995146da1705bebf034a64b1d21f (patch)
tree1132f66da3631ab7be156e63a3300afd42bc90f8
parent2396609e2d90829dcc6e88fcfc099becd1309bc8 (diff)
Add X-Forwarded-For http header to keep source address (#21649)
-rw-r--r--ydb/mvp/oidc_proxy/oidc_proxy_ut.cpp11
-rw-r--r--ydb/mvp/oidc_proxy/openid_connect.cpp47
-rw-r--r--ydb/mvp/oidc_proxy/openid_connect.h2
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 {