Merge 10615 via multiwallet_rpc-28+knots

This commit is contained in:
Luke Dashjr 2025-03-05 03:27:08 +00:00
commit 962511f17b
12 changed files with 194 additions and 44 deletions

View File

@ -102,7 +102,7 @@ static void JSONErrorReply(HTTPRequest* req, UniValue objError, const JSONRPCReq
//This function checks username and password against -rpcauth
//entries from config file.
static bool multiUserAuthorized(std::string strUserPass)
static bool multiUserAuthorized(std::string strUserPass, std::string& out_wallet_restriction)
{
if (strUserPass.find(':') == std::string::npos) {
return false;
@ -127,13 +127,14 @@ static bool multiUserAuthorized(std::string strUserPass)
std::string strHashFromPass = HexStr(hexvec);
if (TimingResistantEqual(strHashFromPass, strHash)) {
out_wallet_restriction = (vFields.size() > 3) ? vFields[3] : "";
return true;
}
}
return false;
}
static bool RPCAuthorized(const std::string& strAuth, std::string& strAuthUsernameOut)
static bool RPCAuthorized(const std::string& strAuth, std::string& strAuthUsernameOut, std::string& out_wallet_restriction)
{
if (strAuth.substr(0, 6) != "Basic ")
return false;
@ -149,9 +150,10 @@ static bool RPCAuthorized(const std::string& strAuth, std::string& strAuthUserna
// Check if authorized under single-user field.
// (strRPCUserColonPass is empty when -norpccookiefile is specified).
if (!strRPCUserColonPass.empty() && TimingResistantEqual(strUserPass, strRPCUserColonPass)) {
out_wallet_restriction = "";
return true;
}
return multiUserAuthorized(strUserPass);
return multiUserAuthorized(strUserPass, out_wallet_restriction);
}
static bool HTTPReq_JSONRPC(const std::any& context, HTTPRequest* req)
@ -172,7 +174,7 @@ static bool HTTPReq_JSONRPC(const std::any& context, HTTPRequest* req)
JSONRPCRequest jreq;
jreq.context = context;
jreq.peerAddr = req->GetPeer().ToStringAddrPort();
if (!RPCAuthorized(authHeader.second, jreq.authUser)) {
if (!RPCAuthorized(authHeader.second, jreq.authUser, jreq.m_wallet_restriction)) {
LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", jreq.peerAddr);
/* Deter brute-forcing
@ -318,17 +320,26 @@ static bool InitRPCAuthentication()
LogPrintf("Config options rpcuser and rpcpassword will soon be deprecated. Locally-run instances may remove rpcuser to use cookie-based auth, or may be replaced with rpcauth. Please see share/rpcauth for rpcauth auth generation.\n");
strRPCUserColonPass = gArgs.GetArg("-rpcuser", "") + ":" + gArgs.GetArg("-rpcpassword", "");
}
constexpr auto AddRPCAuth = [](const std::string& rpcauth) {
std::vector<std::string> fields{SplitString(rpcauth, ':')};
if (fields.size() < 2 || fields.size() > 3) {
return false;
}
const std::vector<std::string> salt_hmac{SplitString(fields[1], '$')};
if (salt_hmac.size() == 2) {
fields.erase(fields.begin() + 1);
fields.insert(fields.begin() + 1, salt_hmac.begin(), salt_hmac.end());
g_rpcauth.push_back(fields);
} else {
return false;
}
return true;
};
if (!(gArgs.IsArgNegated("-rpcauth") || (gArgs.GetArgs("-rpcauth").empty() && gArgs.GetArgs("-rpcauthfile").empty()))) {
LogPrintf("Using rpcauth authentication.\n");
for (const std::string& rpcauth : gArgs.GetArgs("-rpcauth")) {
if (rpcauth.empty()) continue;
std::vector<std::string> fields{SplitString(rpcauth, ':')};
const std::vector<std::string> salt_hmac{SplitString(fields.back(), '$')};
if (fields.size() == 2 && salt_hmac.size() == 2) {
fields.pop_back();
fields.insert(fields.end(), salt_hmac.begin(), salt_hmac.end());
g_rpcauth.push_back(fields);
} else {
if (!AddRPCAuth(rpcauth)) {
LogPrintf("Invalid -rpcauth argument.\n");
return false;
}
@ -338,13 +349,11 @@ static bool InitRPCAuthentication()
file.open(path);
if (!file.is_open()) continue;
std::string rpcauth;
size_t lineno = 0;
while (std::getline(file, rpcauth)) {
std::vector<std::string> fields{SplitString(rpcauth, ':')};
const std::vector<std::string> salt_hmac{SplitString(fields.back(), '$')};
if (fields.size() == 2 && salt_hmac.size() == 2) {
fields.pop_back();
fields.insert(fields.end(), salt_hmac.begin(), salt_hmac.end());
g_rpcauth.push_back(fields);
++lineno;
if (!AddRPCAuth(rpcauth)) {
LogPrintf("WARNING: Invalid line %s in -rpcauthfile=%s; ignoring\n", lineno, path);
}
}
}

View File

@ -676,7 +676,14 @@ void SetupServerArgs(ArgsManager& argsman)
argsman.AddArg("-rest", strprintf("Accept public REST requests (default: %u)", DEFAULT_REST_ENABLE), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
argsman.AddArg("-rpcallowip=<ip>", "Allow JSON-RPC connections from specified source. Valid values for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0), a network/CIDR (e.g. 1.2.3.4/24), all ipv4 (0.0.0.0/0), or all ipv6 (::/0). This option can be specified multiple times", ArgsManager::ALLOW_ANY, 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/rpcauth. 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>[:wallet]",
"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/rpcauth. "
"The client then connects normally using the rpcuser=<USERNAME>/rpcpassword=<PASSWORD> pair of arguments. "
"A single wallet name can also be specified to restrict access to only that wallet, or '-' to deny all wallet access. "
"This option can be specified multiple times",
ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::RPC);
argsman.AddArg("-rpcauthfile=<userpw>", "A file with a single lines with same format as rpcauth. This option can be specified multiple times", ArgsManager::ALLOW_ANY, 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)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::RPC);
argsman.AddArg("-rpcdoccheck", strprintf("Throw a non-fatal error at runtime if the documentation for an RPC is incorrect (default: %u)", DEFAULT_RPC_DOC_CHECK), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);

View File

@ -343,6 +343,7 @@ public:
req.params = params;
req.strMethod = command;
req.URI = uri;
req.m_wallet_restriction.clear();
return ::tableRPC.execute(req);
}
std::vector<std::string> listRpcCommands() override { return ::tableRPC.listCommands(); }

View File

@ -3311,6 +3311,8 @@ static RPCHelpMan dumptxoutset()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
EnsureNotWalletRestricted(request);
// handle optional ASCII parameters
const bool is_human_readable = !request.params[1].isNull();
const bool show_header = request.params[2].isNull() || request.params[2].get_bool();

View File

@ -41,6 +41,7 @@ public:
enum Mode { EXECUTE, GET_HELP, GET_ARGS } mode = EXECUTE;
std::string URI;
std::string authUser;
std::string m_wallet_restriction{"-"};
std::string peerAddr;
std::any context;
JSONRPCVersion m_json_version = JSONRPCVersion::V1_LEGACY;

View File

@ -1455,3 +1455,19 @@ void PushWarnings(const std::vector<bilingual_str>& warnings, UniValue& obj)
if (warnings.empty()) return;
obj.pushKV("warnings", BilingualStringsToUniValue(warnings));
}
bool GetWalletRestrictionFromJSONRPCRequest(const JSONRPCRequest& request, std::string& out_wallet_allowed)
{
if (request.m_wallet_restriction.empty()) return false;
out_wallet_allowed = request.m_wallet_restriction;
return true;
}
void EnsureNotWalletRestricted(const JSONRPCRequest& request)
{
std::string authorized_wallet_name;
const bool have_wallet_restriction = GetWalletRestrictionFromJSONRPCRequest(request, authorized_wallet_name);
if (have_wallet_restriction) {
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not available for wallet-restricted RPC users");
}
}

View File

@ -545,4 +545,7 @@ std::vector<RPCResult> ScriptPubKeyDoc();
void PushWarnings(const UniValue& warnings, UniValue& obj);
void PushWarnings(const std::vector<bilingual_str>& warnings, UniValue& obj);
bool GetWalletRestrictionFromJSONRPCRequest(const JSONRPCRequest& request, std::string& out_wallet_allowed);
void EnsureNotWalletRestricted(const JSONRPCRequest& request);
#endif // BITCOIN_RPC_UTIL_H

View File

@ -545,6 +545,8 @@ RPCHelpMan importwallet()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
EnsureNotWalletRestricted(request);
std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
if (!pwallet) return UniValue::VNULL;
@ -784,6 +786,8 @@ RPCHelpMan dumpwallet()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
EnsureNotWalletRestricted(request);
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
if (!pwallet) return UniValue::VNULL;
@ -1995,6 +1999,8 @@ RPCHelpMan backupwallet()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
EnsureNotWalletRestricted(request);
const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
if (!pwallet) return UniValue::VNULL;
@ -2045,6 +2051,7 @@ RPCHelpMan restorewallet()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
EnsureNotWalletRestricted(request);
WalletContext& context = EnsureWalletContext(request.context);

View File

@ -5,6 +5,7 @@
#include <wallet/rpc/util.h>
#include <common/url.h>
#include <httprpc.h>
#include <rpc/util.h>
#include <util/any.h>
#include <util/translation.h>
@ -64,18 +65,43 @@ std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& reques
CHECK_NONFATAL(request.mode == JSONRPCRequest::EXECUTE);
WalletContext& context = EnsureWalletContext(request.context);
std::string wallet_name;
if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
std::shared_ptr<CWallet> pwallet = GetWallet(context, wallet_name);
if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
bool have_wallet_restriction;
std::string authorized_wallet_name;
have_wallet_restriction = GetWalletRestrictionFromJSONRPCRequest(request, authorized_wallet_name);
bool have_requested_wallet;
std::string requested_wallet_name;
have_requested_wallet = GetWalletNameFromJSONRPCRequest(request, requested_wallet_name);
std::shared_ptr<CWallet> pwallet;
size_t count{0};
if (!have_wallet_restriction) {
// Any wallet is permitted; select by endpoint, or use the sole wallet
if (have_requested_wallet) {
pwallet = GetWallet(context, requested_wallet_name);
} else {
auto wallet = GetDefaultWallet(context, count);
if (wallet) pwallet = wallet;
}
} else if (authorized_wallet_name == "-") {
// Block wallet access always
} else if ((!have_requested_wallet) || requested_wallet_name == authorized_wallet_name) {
// Select specifically the authorized wallet
pwallet = GetWallet(context, authorized_wallet_name);
}
if (pwallet) {
return pwallet;
}
size_t count{0};
auto wallet = GetDefaultWallet(context, count);
if (wallet) return wallet;
if (count == 0) {
if (have_requested_wallet) {
throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
}
if (have_wallet_restriction
? (authorized_wallet_name == "-" || !GetWallet(context, authorized_wallet_name))
: (count == 0)
) {
throw JSONRPCError(
RPC_WALLET_NOT_FOUND, "No wallet is loaded. Load a wallet using loadwallet or create a new one with createwallet. (Note: A default wallet is no longer automatically created)");
}

View File

@ -245,6 +245,14 @@ static RPCHelpMan loadwallet()
WalletContext& context = EnsureWalletContext(request.context);
const std::string name(request.params[0].get_str());
{
std::string authorized_wallet_name;
const bool have_wallet_restriction = GetWalletRestrictionFromJSONRPCRequest(request, authorized_wallet_name);
if (have_wallet_restriction && authorized_wallet_name != name) {
throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Wallet usage is restricted.");
}
}
DatabaseOptions options;
DatabaseStatus status;
ReadDatabaseArgs(*context.args, options);
@ -385,6 +393,14 @@ static RPCHelpMan createwallet()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
{
std::string authorized_wallet_name;
const bool have_wallet_restriction = GetWalletRestrictionFromJSONRPCRequest(request, authorized_wallet_name);
if (have_wallet_restriction && authorized_wallet_name != request.params[0].get_str()) {
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet usage is restricted.");
}
}
WalletContext& context = EnsureWalletContext(request.context);
uint64_t flags = 0;
if (!request.params[1].isNull() && request.params[1].get_bool()) {
@ -487,7 +503,14 @@ static RPCHelpMan unloadwallet()
}
WalletContext& context = EnsureWalletContext(request.context);
std::shared_ptr<CWallet> wallet = GetWallet(context, wallet_name);
std::shared_ptr<CWallet> wallet;
{
std::string authorized_wallet_name;
const bool have_wallet_restriction = GetWalletRestrictionFromJSONRPCRequest(request, authorized_wallet_name);
if ((!have_wallet_restriction) || authorized_wallet_name == wallet_name) {
wallet = GetWallet(context, wallet_name);
}
}
if (!wallet) {
throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
}
@ -789,6 +812,9 @@ static RPCHelpMan migratewallet()
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
// New wallets do not necessarily have the same name as the migrated wallet
EnsureNotWalletRestricted(request);
std::string wallet_name;
if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
if (!(request.params[0].isNull() || request.params[0].get_str() == wallet_name)) {

View File

@ -239,6 +239,7 @@ BOOST_FIXTURE_TEST_CASE(importmulti_rescan, TestChain100Setup)
keys.push_back(std::move(key));
JSONRPCRequest request;
request.context = &context;
request.m_wallet_restriction = "";
request.params.setArray();
request.params.push_back(std::move(keys));
@ -294,6 +295,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
}
JSONRPCRequest request;
request.context = &context;
request.m_wallet_restriction = "";
request.params.setArray();
request.params.push_back(backup_file);
@ -312,6 +314,7 @@ BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
context.args = &m_args;
JSONRPCRequest request;
request.context = &context;
request.m_wallet_restriction = "";
request.params.setArray();
request.params.push_back(backup_file);
AddWallet(context, wallet);

View File

@ -23,19 +23,23 @@ import sys
from typing import Optional
def call_with_auth(node, user, password, method="getbestblockhash"):
def call_with_auth(node, user, password, *, uripath='/', method='getbestblockhash'):
url = urllib.parse.urlparse(node.url)
headers = {"Authorization": "Basic " + str_to_b64str('{}:{}'.format(user, password))}
conn = http.client.HTTPConnection(url.hostname, url.port)
conn.connect()
conn.request('POST', '/', f'{{"method": "{method}"}}', headers)
conn.request('POST', uripath, f'{{"method": "{method}"}}', headers)
resp = conn.getresponse()
resp.data = resp.read()
conn.close()
return resp
class HTTPBasicsTest(BitcoinTestFramework):
def add_options(self, parser):
self.add_wallet_options(parser)
def set_test_params(self):
self.num_nodes = 2
self.supports_cli = False
@ -86,15 +90,34 @@ class HTTPBasicsTest(BitcoinTestFramework):
lines = p.stdout.read().splitlines()
self.authinfo.append( (username, lines[1]) )
def gen_userpass(username_prefix, wallet_restrictions=None):
username = username_prefix + '_' + ''.join(SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(10))
p = subprocess.Popen([sys.executable, gen_rpcauth, username], stdout=subprocess.PIPE, universal_newlines=True)
lines = p.stdout.read().splitlines()
assert "\n" not in lines[1]
assert lines[1][:8] == 'rpcauth='
config_line = lines[1]
self.authinfo.append( (username, lines[3], wallet_restrictions) )
if not (wallet_restrictions is None):
config_line += ":" + wallet_restrictions
return config_line + "\n"
# Hand-generated rpcauthfile with one entry and no newline
username = 'rpcauth_nonewline_' + ''.join(SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(10))
p = subprocess.Popen([sys.executable, gen_rpcauth, username], stdout=subprocess.PIPE, universal_newlines=True)
lines = p.stdout.read().splitlines()
assert "\n" not in lines[1]
assert lines[1][:8] == 'rpcauth='
with open(Path(self.options.tmpdir) / 'rpcauth_nonewline', "a", encoding='utf8') as f:
f.write(lines[1][8:])
self.authinfo.append( (username, lines[3]) )
f.write(gen_userpass('rpcauth_nonewline')[8:-1])
if self.is_wallet_compiled():
# Hand-generated rpcauthfile with wallet restrictions
with open(Path(self.options.tmpdir) / 'rpcauth_walletrestricted', "a", encoding='utf8') as f:
f.write(gen_userpass('rpcauth_walletrestricted_allow_all', '')[8:])
f.write(gen_userpass('rpcauth_walletrestricted_allow_none', '-')[8:])
f.write(gen_userpass('rpcauth_walletrestricted_allow_one', 'limitedwallet1')[8:])
# Uses the same username as a privileged one, but with different passwords:
f.write(gen_userpass('rpcauth_walletrestricted_allow_all', 'limitedwallet1')[8:])
f.write(gen_userpass('rpcauth_walletrestricted_allow_all', 'limitedwallet2')[8:])
f.write(gen_userpass('rpcauth_walletrestricted_allow_all', '-')[8:])
f.write(gen_userpass('rpcauth_walletrestricted_allow_one', 'limitedwallet2')[8:])
f.write(gen_userpass('rpcauth_walletrestricted_allow_one', '-')[8:])
with open(self.nodes[0].datadir_path / "bitcoin.conf", "a", encoding="utf8") as f:
f.write(rpcauth + "\n")
@ -103,14 +126,25 @@ class HTTPBasicsTest(BitcoinTestFramework):
f.write("rpcauthfile=rpcauth_single\n")
f.write("rpcauthfile=rpcauth_multi\n")
f.write("rpcauthfile=rpcauth_nonewline\n")
if self.is_wallet_compiled():
f.write("rpcauthfile=rpcauth_walletrestricted\n")
f.write(gen_userpass('rpcauth_walletrestricted2_allow_all', '') + "\n")
f.write(gen_userpass('rpcauth_walletrestricted2_allow_none', '-') + "\n")
f.write(gen_userpass('rpcauth_walletrestricted2_allow_one', 'limitedwallet1') + "\n")
# Uses the same username as a privileged one, but with different passwords:
f.write(gen_userpass('rpcauth_walletrestricted2_allow_all', 'limitedwallet1') + "\n")
f.write(gen_userpass('rpcauth_walletrestricted2_allow_all', 'limitedwallet2') + "\n")
f.write(gen_userpass('rpcauth_walletrestricted2_allow_all', '-') + "\n")
f.write(gen_userpass('rpcauth_walletrestricted2_allow_one', 'limitedwallet2') + "\n")
f.write(gen_userpass('rpcauth_walletrestricted2_allow_one', '-') + "\n")
with open(self.nodes[1].datadir_path / "bitcoin.conf", "a", encoding="utf8") as f:
f.write("rpcuser={}\n".format(self.rpcuser))
f.write("rpcpassword={}\n".format(self.rpcpassword))
self.restart_node(0)
self.restart_node(1)
def test_auth(self, node, user, password):
self.log.info('Correct...')
def test_auth(self, node, user, password, wallet_restrictions=None):
self.log.info('Correct... %s (wallet_restrictions=%s)' % (user, wallet_restrictions))
assert_equal(200, call_with_auth(node, user, password).status)
self.log.info('Wrong...')
@ -122,6 +156,17 @@ class HTTPBasicsTest(BitcoinTestFramework):
self.log.info('Wrong...')
assert_equal(401, call_with_auth(node, user + 'wrong', password + 'wrong').status)
if not (wallet_restrictions is None):
for n in range(1, 3):
wallet_name = f'limitedwallet{n}'
self.log.info(f'{wallet_name}...')
resp = call_with_auth(node, user, password, uripath=f'/wallet/{wallet_name}', method='getwalletinfo')
if wallet_restrictions in ('', f'{wallet_name}'):
assert_equal(200, resp.status)
else:
assert_equal(500, resp.status)
assert b'"Requested wallet does not exist or is not loaded"' in resp.data
def test_rpccookieperms(self):
p = {"owner": 0o600, "group": 0o640, "all": 0o644}
@ -180,6 +225,10 @@ class HTTPBasicsTest(BitcoinTestFramework):
self.log.info('Check correctness of the rpcauth config option')
url = urllib.parse.urlparse(self.nodes[0].url)
if self.is_wallet_compiled():
self.nodes[0].createwallet('limitedwallet1')
self.nodes[0].createwallet('limitedwallet2')
self.test_auth(self.nodes[0], url.username, url.password)
self.test_auth(self.nodes[0], 'rt', self.rtpassword)
self.test_auth(self.nodes[0], 'rt2', self.rt2password)
@ -204,33 +253,33 @@ class HTTPBasicsTest(BitcoinTestFramework):
assert_equal(200, call_with_auth(self.nodes[0], 'def', 'abc').status)
assert_equal(200, call_with_auth(self.nodes[0], 'rt', self.rtpassword).status)
for info in self.authinfo:
assert_equal(200, call_with_auth(self.nodes[0], *info).status)
assert_equal(200, call_with_auth(self.nodes[0], *info[:2]).status)
self.log.info('Check -norpcauth disables all previous -rpcauth* params')
self.restart_node(0, extra_args=[rpcauth_def, '-norpcauth'])
assert_equal(401, call_with_auth(self.nodes[0], 'def', 'abc').status)
assert_equal(401, call_with_auth(self.nodes[0], 'rt', self.rtpassword).status)
for info in self.authinfo:
assert_equal(401, call_with_auth(self.nodes[0], *info).status)
assert_equal(401, call_with_auth(self.nodes[0], *info[:2]).status)
self.log.info('Check -norpcauth can be reversed with -rpcauth')
self.restart_node(0, extra_args=[rpcauth_def, '-norpcauth', '-rpcauth'])
# FIXME: assert_equal(200, call_with_auth(self.nodes[0], 'def', 'abc').status)
assert_equal(200, call_with_auth(self.nodes[0], 'rt', self.rtpassword).status)
for info in self.authinfo:
assert_equal(200, call_with_auth(self.nodes[0], *info).status)
assert_equal(200, call_with_auth(self.nodes[0], *info[:2]).status)
self.log.info('Check -norpcauth followed by a specific -rpcauth=* restores config file -rpcauth=* values too')
self.restart_node(0, extra_args=[rpcauth_def, '-norpcauth', rpcauth_abc])
assert_equal(401, call_with_auth(self.nodes[0], 'def', 'abc').status)
assert_equal(200, call_with_auth(self.nodes[0], 'rt', self.rtpassword).status)
for info in self.authinfo:
assert_equal(200, call_with_auth(self.nodes[0], *info).status)
assert_equal(200, call_with_auth(self.nodes[0], *info[:2]).status)
self.restart_node(0, extra_args=[rpcauth_def, '-norpcauth', '-rpcauth='])
assert_equal(401, call_with_auth(self.nodes[0], 'def', 'abc').status)
assert_equal(200, call_with_auth(self.nodes[0], 'rt', self.rtpassword).status)
for info in self.authinfo:
assert_equal(200, call_with_auth(self.nodes[0], *info).status)
assert_equal(200, call_with_auth(self.nodes[0], *info[:2]).status)
self.log.info('Check -rpcauth are validated')
self.stop_node(0)