mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 12:32:48 +01:00
feat: rpc external users are comma separated list
This commit is contained in:
parent
68def970ad
commit
241f073932
@ -154,6 +154,8 @@ static struct evhttp* eventHTTP = nullptr;
|
|||||||
static std::vector<CSubNet> rpc_allow_subnets;
|
static std::vector<CSubNet> rpc_allow_subnets;
|
||||||
//! Work queue for handling longer requests off the event loop thread
|
//! Work queue for handling longer requests off the event loop thread
|
||||||
static std::unique_ptr<WorkQueue<HTTPClosure>> g_work_queue{nullptr};
|
static std::unique_ptr<WorkQueue<HTTPClosure>> g_work_queue{nullptr};
|
||||||
|
//! List of 'external' RPC users
|
||||||
|
static std::vector<std::string> g_external_usernames;
|
||||||
//! Handlers for (sub)paths
|
//! Handlers for (sub)paths
|
||||||
static std::vector<HTTPPathHandler> pathHandlers;
|
static std::vector<HTTPPathHandler> pathHandlers;
|
||||||
//! Bound listening sockets
|
//! Bound listening sockets
|
||||||
@ -270,8 +272,7 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const bool is_external_request = [&hreq]() -> bool {
|
const bool is_external_request = [&hreq]() -> bool {
|
||||||
const std::string external_username = gArgs.GetArg("-rpcexternaluser", "");
|
if (g_external_usernames.empty()) return false;
|
||||||
if (external_username.empty()) return false;
|
|
||||||
|
|
||||||
const std::string strAuth = hreq->GetHeader("authorization").second;
|
const std::string strAuth = hreq->GetHeader("authorization").second;
|
||||||
if (strAuth.substr(0, 6) != "Basic ")
|
if (strAuth.substr(0, 6) != "Basic ")
|
||||||
@ -283,8 +284,8 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
|
|||||||
if (invalid) return false;
|
if (invalid) return false;
|
||||||
|
|
||||||
if (strUserPass.find(':') == std::string::npos) return false;
|
if (strUserPass.find(':') == std::string::npos) return false;
|
||||||
|
const std::string username{strUserPass.substr(0, strUserPass.find(':'))};
|
||||||
return strUserPass.substr(0, strUserPass.find(':')) == external_username;
|
return find(g_external_usernames.begin(), g_external_usernames.end(), username) != g_external_usernames.end();
|
||||||
}();
|
}();
|
||||||
|
|
||||||
// Dispatch to worker thread
|
// Dispatch to worker thread
|
||||||
@ -432,12 +433,11 @@ bool InitHTTPServer()
|
|||||||
LogPrint(BCLog::HTTP, "Initialized HTTP server\n");
|
LogPrint(BCLog::HTTP, "Initialized HTTP server\n");
|
||||||
int workQueueDepth = std::max((long)gArgs.GetArg("-rpcworkqueue", DEFAULT_HTTP_WORKQUEUE), 1L);
|
int workQueueDepth = std::max((long)gArgs.GetArg("-rpcworkqueue", DEFAULT_HTTP_WORKQUEUE), 1L);
|
||||||
int workQueueDepthExternal = 0;
|
int workQueueDepthExternal = 0;
|
||||||
if (!gArgs.GetArg("-rpcexternaluser", "").empty()) {
|
if (const std::string rpc_externaluser{gArgs.GetArg("-rpcexternaluser", "")}; !rpc_externaluser.empty()) {
|
||||||
LogPrintf("HTTP: creating external work queue of depth %d\n", workQueueDepthExternal);
|
|
||||||
workQueueDepthExternal = std::max((long)gArgs.GetArg("-rpcexternalworkqueue", DEFAULT_HTTP_WORKQUEUE), 1L);
|
workQueueDepthExternal = std::max((long)gArgs.GetArg("-rpcexternalworkqueue", DEFAULT_HTTP_WORKQUEUE), 1L);
|
||||||
|
g_external_usernames = SplitString(rpc_externaluser, ',');
|
||||||
}
|
}
|
||||||
LogPrintf("HTTP: creating work queue of depth %d external_depth %d\n", workQueueDepth, workQueueDepthExternal);
|
LogPrintf("HTTP: creating work queue of depth %d external_depth %d\n", workQueueDepth, workQueueDepthExternal);
|
||||||
|
|
||||||
g_work_queue = std::make_unique<WorkQueue<HTTPClosure>>(workQueueDepth, workQueueDepthExternal);
|
g_work_queue = std::make_unique<WorkQueue<HTTPClosure>>(workQueueDepth, workQueueDepthExternal);
|
||||||
// transfer ownership to eventBase/HTTP via .release()
|
// transfer ownership to eventBase/HTTP via .release()
|
||||||
eventBase = base_ctr.release();
|
eventBase = base_ctr.release();
|
||||||
|
@ -764,7 +764,7 @@ void SetupServerArgs(NodeContext& node)
|
|||||||
argsman.AddArg("-rpcauth=<userpw>", "Username and HMAC-SHA-256 hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This option can be specified multiple times", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
|
argsman.AddArg("-rpcauth=<userpw>", "Username and HMAC-SHA-256 hashed password for JSON-RPC connections. The field <userpw> comes in the format: <USERNAME>:<SALT>$<HASH>. A canonical python script is included in share/rpcuser. The client then connects normally using the rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. This option can be specified multiple times", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpcbind=<addr>[:port]", "Bind to given address to listen for JSON-RPC connections. Do not expose the RPC server to untrusted networks such as the public internet! This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost, or if -rpcallowip has been specified, 0.0.0.0 and :: i.e., all addresses)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
|
argsman.AddArg("-rpcbind=<addr>[:port]", "Bind to given address to listen for JSON-RPC connections. Do not expose the RPC server to untrusted networks such as the public internet! This option is ignored unless -rpcallowip is also passed. Port is optional and overrides -rpcport. Use [host]:port notation for IPv6. This option can be specified multiple times (default: 127.0.0.1 and ::1 i.e., localhost, or if -rpcallowip has been specified, 0.0.0.0 and :: i.e., all addresses)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpccookiefile=<loc>", "Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
argsman.AddArg("-rpccookiefile=<loc>", "Location of the auth cookie. Relative paths will be prefixed by a net-specific datadir location. (default: data dir)", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpcexternaluser=<user>", "Username for JSON-RPC external connections", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
|
argsman.AddArg("-rpcexternaluser=<users>", "List of comma-separated usernames for JSON-RPC external connections", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpcexternalworkqueue=<n>", strprintf("Set the depth of the work queue to service external RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
|
argsman.AddArg("-rpcexternalworkqueue=<n>", strprintf("Set the depth of the work queue to service external RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpcpassword=<pw>", "Password for JSON-RPC connections", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
|
argsman.AddArg("-rpcpassword=<pw>", "Password for JSON-RPC connections", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
|
||||||
argsman.AddArg("-rpcport=<port>", strprintf("Listen for JSON-RPC connections on <port> (default: %u, testnet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
|
argsman.AddArg("-rpcport=<port>", strprintf("Listen for JSON-RPC connections on <port> (default: %u, testnet: %u, regtest: %u)", defaultBaseParams->RPCPort(), testnetBaseParams->RPCPort(), regtestBaseParams->RPCPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
|
||||||
|
@ -114,7 +114,7 @@ class HTTPBasicsTest(BitcoinTestFramework):
|
|||||||
test_command("debug", ["1"], rpcuser_authpair_operator, 200)
|
test_command("debug", ["1"], rpcuser_authpair_operator, 200)
|
||||||
|
|
||||||
|
|
||||||
self.log.info("Restart node with -rpcexternaluser...")
|
self.log.info("Restart node with -rpcexternaluser")
|
||||||
self.restart_node(0, extra_args=["-rpcexternaluser=platform-user"])
|
self.restart_node(0, extra_args=["-rpcexternaluser=platform-user"])
|
||||||
|
|
||||||
external_log_str = "HTTP: Calling handler for external user"
|
external_log_str = "HTTP: Calling handler for external user"
|
||||||
@ -124,6 +124,13 @@ class HTTPBasicsTest(BitcoinTestFramework):
|
|||||||
with self.nodes[0].assert_debug_log(expected_msgs=[expected_log_str], unexpected_msgs = [external_log_str]):
|
with self.nodes[0].assert_debug_log(expected_msgs=[expected_log_str], unexpected_msgs = [external_log_str]):
|
||||||
test_command("getbestblockhash", [], rpcuser_authpair_operator, 200)
|
test_command("getbestblockhash", [], rpcuser_authpair_operator, 200)
|
||||||
|
|
||||||
|
self.log.info("Restart node with multiple external users")
|
||||||
|
self.restart_node(0, extra_args=["-rpcexternaluser=platform-user,operator"])
|
||||||
|
with self.nodes[0].assert_debug_log(expected_msgs=[expected_log_str, external_log_str]):
|
||||||
|
test_command("getbestblockhash", [], rpcuser_authpair_platform, 200)
|
||||||
|
with self.nodes[0].assert_debug_log(expected_msgs=[expected_log_str, external_log_str]):
|
||||||
|
test_command("getbestblockhash", [], rpcuser_authpair_operator, 200)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
Loading…
Reference in New Issue
Block a user