Skip to content

Commit

Permalink
Add http basic authorization
Browse files Browse the repository at this point in the history
  • Loading branch information
Jackarain committed May 30, 2024
1 parent 5fb6e97 commit b734555
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 6 deletions.
85 changes: 79 additions & 6 deletions proxy/include/proxy/proxy_server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,15 @@ R"x*x*x(<html>
<center><h1>400 Bad Request</h1></center>
<hr><center>nginx/1.20.2</center>
</body>
</html>)x*x*x";

inline const char* fake_401_content =
R"x*x*x(<html>
<head><title>401 Authorization Required</title></head>
<body>
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx/1.20.2</center>
</body>
</html>)x*x*x";

inline const char* fake_403_content =
Expand Down Expand Up @@ -387,6 +396,10 @@ R"x*x*x(<html>
// 示.
bool autoindex_;

// 用于指定是否启用 http basic auth 认证, 默认为 false,
// 即不启用, 如果启用, 则需要设置 auth_users_ 参数.
bool htpasswd_{ false };

// 禁用 http 服务, 客户端无法通过明文的 http 协议与之通信, 包括
// ssl 加密的 https 以及不加密的 http 服务, 同时也包括 http(s)
// proxy 也会被禁用.
Expand Down Expand Up @@ -481,7 +494,7 @@ R"x*x*x(<html>
PROXY_AUTH_ILLEGAL,
};

inline std::string proxy_auth_error_message(int code) const
inline std::string pauth_error_message(int code) const
{
switch (code)
{
Expand Down Expand Up @@ -2045,7 +2058,7 @@ R"x*x*x(<html>
co_return;
}

inline int http_proxy_authorization(std::string_view pa)
inline int http_authorization(std::string_view pa)
{
if (m_option.auth_users_.empty())
return PROXY_AUTH_SUCCESS;
Expand Down Expand Up @@ -2146,15 +2159,15 @@ R"x*x*x(<html>

// http 代理认证, 如果请求的 rarget 不是 http url 或认证
// 失败, 则按正常 web 请求处理.
auto auth = http_proxy_authorization(pa);
auto auth = http_authorization(pa);
if (auth != PROXY_AUTH_SUCCESS || expect_url.has_error())
{
if (!expect_url.has_error())
{
XLOG_WARN << "connection id: "
<< m_connection_id
<< ", proxy err: "
<< proxy_auth_error_message(auth);
<< pauth_error_message(auth);

co_return !first;
}
Expand All @@ -2164,6 +2177,36 @@ R"x*x*x(<html>
if (m_option.doc_directory_.empty())
co_return !first;

// htpasswd 表示需要用户认证.
if (m_option.htpasswd_)
{
// 处理 http 认证, 如果客户没有传递认证信息, 则返回 401.
// 如果用户认证信息没有设置, 则直接返回 401.
auto auth = req[http::field::authorization];
if (auth.empty() || m_option.auth_users_.empty())
{
XLOG_WARN << "connection id: "
<< m_connection_id
<< ", auth error: "
<< (auth.empty() ? "no auth" : "no user");

co_await unauthorized_http_route(req);
co_return true;
}

auto auth_result = http_authorization(auth);
if (auth_result != PROXY_AUTH_SUCCESS)
{
XLOG_WARN << "connection id: "
<< m_connection_id
<< ", auth error: "
<< pauth_error_message(auth_result);

co_await unauthorized_http_route(req);
co_return true;
}
}

// 如果不允许目录索引, 检查请求的是否为文件, 如果是具体文件则按文
// 件请求处理, 否则返回 403.
if (!m_option.autoindex_)
Expand Down Expand Up @@ -2319,13 +2362,13 @@ R"x*x*x(<html>
: ", proxy_authorization: " + pa);

// http 代理认证.
auto auth = http_proxy_authorization(pa);
auto auth = http_authorization(pa);
if (auth != PROXY_AUTH_SUCCESS)
{
XLOG_WARN << "connection id: "
<< m_connection_id
<< ", proxy err: "
<< proxy_auth_error_message(auth);
<< pauth_error_message(auth);

auto fake_page = fmt::vformat(fake_407_content_fmt,
fmt::make_format_args(server_date_string()));
Expand Down Expand Up @@ -4034,6 +4077,36 @@ R"x*x*x(<html>
<< ", forbidden http route err: "
<< ec.message();
}

co_return;
}

inline net::awaitable<void> unauthorized_http_route(const string_request& request)
{
boost::system::error_code ec;

string_response res{ http::status::unauthorized, request.version() };
res.set(http::field::server, version_string);
res.set(http::field::date, server_date_string());
res.set(http::field::content_type, "text/html; charset=UTF-8");
res.set(http::field::www_authenticate, "Basic realm=\"proxy\"");

res.keep_alive(true);
res.body() = fake_401_content;
res.prepare_payload();

http::serializer<false, string_body, http::fields> sr(res);
co_await http::async_write(
m_local_socket, sr, net_awaitable[ec]);
if (ec)
{
XLOG_WARN << "connection id: "
<< m_connection_id
<< ", unauthorized http route err: "
<< ec.message();
}

co_return;
}

private:
Expand Down
8 changes: 8 additions & 0 deletions server/proxy_server/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,14 @@ std::string ssl_sni;

bool transparent = false;
bool autoindex = false;
bool htpasswd = false;

bool disable_http = false;
bool disable_insecure = true;
bool disable_logs;
bool disable_socks = false;
bool disable_udp = false;

bool happyeyeballs = true;
bool connect_v6only = false;
bool connect_v4only = false;
Expand Down Expand Up @@ -150,6 +153,7 @@ start_proxy_server(net::io_context& ioc, server_ptr& server)

opt.doc_directory_ = doc_dir;
opt.autoindex_ = autoindex;
opt.htpasswd_ = htpasswd;

server = proxy_server::make(
ioc.get_executor(), listen, opt);
Expand Down Expand Up @@ -291,13 +295,17 @@ int main(int argc, char** argv)

("ipip_db", po::value<std::string>(&ipip_db)->value_name("")->default_value("17monipdb.datx"), "Specify ipip database filename.")
("http_doc", po::value<std::string>(&doc_dir)->value_name("doc"), "Specify document root directory for HTTP server.")
("htpasswd", po::value<bool>(&htpasswd)->value_name("")->default_value(false), "Enable WWW-Authenticate for HTTP server.")

("autoindex", po::value<bool>(&autoindex)->default_value(false), "Enable directory listing.")
("logs_path", po::value<std::string>(&log_dir)->value_name(""), "Specify directory for log files.")

("disable_logs", po::value<bool>(&disable_logs)->value_name(""), "Disable logging.")
("disable_http", po::value<bool>(&disable_http)->value_name("")->default_value(false), "Disable HTTP protocol.")
("disable_socks", po::value<bool>(&disable_socks)->value_name("")->default_value(false), "Disable SOCKS proxy protocol.")
("disable_udp", po::value<bool>(&disable_udp)->value_name("")->default_value(false), "Disable UDP protocol.")
("disable_insecure", po::value<bool>(&disable_insecure)->value_name("")->default_value(false), "Disable insecure protocol.")

("scramble", po::value<bool>(&scramble)->value_name("")->default_value(false), "Noise-based data security.")
("noise_length", po::value<uint16_t>(&noise_length)->value_name("length")->default_value(0x0fff), "Length of the noise data.")
;
Expand Down

0 comments on commit b734555

Please sign in to comment.