auth_use_forwarded_address config setting added, using forwarded address for proxied TCP and HTTP connection, likely bug is fixed in AccessControl, relevant test is appended

This commit is contained in:
Yakov Olkhovskiy 2022-12-20 17:39:40 +00:00
parent a98ce7d2be
commit 9092134544
6 changed files with 60 additions and 3 deletions

View File

@ -568,7 +568,8 @@ std::shared_ptr<const ContextAccess> AccessControl::getContextAccess(
/// Extract the last entry from comma separated list of X-Forwarded-For addresses.
/// Only the last proxy can be trusted (if any).
Strings forwarded_addresses;
boost::split(forwarded_addresses, client_info.forwarded_for, boost::is_any_of(","));
if (!client_info.forwarded_for.empty())
boost::split(forwarded_addresses, client_info.forwarded_for, boost::is_any_of(","));
if (!forwarded_addresses.empty())
{
String & last_forwarded_address = forwarded_addresses.back();

View File

@ -27,6 +27,8 @@
#include <Common/setThreadName.h>
#include <Common/typeid_cast.h>
#include <Parsers/ASTSetQuery.h>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <base/getFQDNOrHostName.h>
#include <base/scope_guard.h>
@ -41,6 +43,7 @@
#include <Poco/MemoryStream.h>
#include <Poco/StreamCopier.h>
#include <Poco/String.h>
#include <Poco/Net/SocketAddress.h>
#include <chrono>
#include <sstream>
@ -469,9 +472,21 @@ bool HTTPHandler::authenticateUser(
client_info.forwarded_for = request.get("X-Forwarded-For", "");
client_info.quota_key = quota_key;
/// Extract the last entry from comma separated list of forwarded_for addresses.
/// Only the last proxy can be trusted (if any).
Strings forwarded_addresses;
if (!client_info.forwarded_for.empty())
boost::split(forwarded_addresses, client_info.forwarded_for, boost::is_any_of(","));
try
{
session->authenticate(*request_credentials, request.clientAddress());
if (!forwarded_addresses.empty() && server.config().getBool("auth_use_forwarded_address", false))
{
boost::trim(forwarded_addresses.back());
session->authenticate(*request_credentials, Poco::Net::SocketAddress(forwarded_addresses.back(), request.clientAddress().port()));
}
else
session->authenticate(*request_credentials, request.clientAddress());
}
catch (const Authentication::Require<BasicCredentials> & required_credentials)
{

View File

@ -9,6 +9,7 @@
#include <base/types.h>
#include <base/scope_guard.h>
#include <Poco/Net/NetException.h>
#include <Poco/Net/SocketAddress.h>
#include <Poco/Util/LayeredConfiguration.h>
#include <Common/CurrentThread.h>
#include <Common/Stopwatch.h>
@ -44,6 +45,8 @@
#include <Common/logger_useful.h>
#include <Common/CurrentMetrics.h>
#include <fmt/format.h>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <Processors/Executors/PullingAsyncPipelineExecutor.h>
#include <Processors/Executors/PushingPipelineExecutor.h>
@ -1151,7 +1154,20 @@ void TCPHandler::receiveHello()
}
session = makeSession();
session->authenticate(user, password, socket().peerAddress());
auto & client_info = session->getClientInfo();
/// Extract the last entry from comma separated list of forwarded_for addresses.
/// Only the last proxy can be trusted (if any).
Strings forwarded_addresses;
if (!client_info.forwarded_for.empty())
boost::split(forwarded_addresses, client_info.forwarded_for, boost::is_any_of(","));
if (!forwarded_addresses.empty() && server.config().getBool("auth_use_forwarded_address", false))
{
boost::trim(forwarded_addresses.back());
session->authenticate(user, password, Poco::Net::SocketAddress(forwarded_addresses.back(), socket().peerAddress().port()));
}
else
session->authenticate(user, password, socket().peerAddress());
}
void TCPHandler::receiveAddendum()

View File

@ -1,4 +1,5 @@
<clickhouse>
<auth_use_forwarded_address>true</auth_use_forwarded_address>
<!-- Used with https_port and tcp_port_secure. Full ssl options list: https://github.com/ClickHouse-Extras/poco/blob/master/NetSSL_OpenSSL/include/Poco/Net/SSLManager.h#L71 -->
<openSSL>
<server> <!-- Used for https server AND secure tcp port -->

View File

@ -12,5 +12,12 @@
</networks>
<profile>default</profile>
</default>
<user123>
<password></password>
<networks replace="replace">
<ip>123.123.123.123</ip>
</networks>
<profile>default</profile>
</user123>
</users>
</clickhouse>

View File

@ -92,3 +92,20 @@ def test_connections():
)
>= 0
)
data_user_allowed = "PROXY TCP4 123.123.123.123 255.255.255.255 65535 65535\r\n\0\021ClickHouse client\024\r\253\251\003\0\007user123\0\004\001\0\001\0\0\t0.0.0.0:0\001\tmilovidov\021milovidov-desktop\vClickHouse \024\r\253\251\003\0\001\0\0\0\002\001\025SELECT 'Hello, world'\002\0\247\203\254l\325\\z|\265\254F\275\333\206\342\024\202\024\0\0\0\n\0\0\0\240\01\0\02\377\377\377\377\0\0\0"
assert (
netcat(server.ip_address, 9100, bytearray(data_user_allowed, "latin-1")).find(
bytearray("Hello, world", "latin-1")
)
>= 0
)
data_user_restricted = "PROXY TCP4 127.0.0.1 255.255.255.255 65535 65535\r\n\0\021ClickHouse client\024\r\253\251\003\0\007user123\0\004\001\0\001\0\0\t0.0.0.0:0\001\tmilovidov\021milovidov-desktop\vClickHouse \024\r\253\251\003\0\001\0\0\0\002\001\025SELECT 'Hello, world'\002\0\247\203\254l\325\\z|\265\254F\275\333\206\342\024\202\024\0\0\0\n\0\0\0\240\01\0\02\377\377\377\377\0\0\0"
assert (
netcat(server.ip_address, 9100, bytearray(data_user_restricted, "latin-1")).find(
bytearray("Exception: user123: Authentication failed", "latin-1")
)
>= 0
)