Merge #10533: [tests] Use cookie auth instead of rpcuser and rpcpassword

279fde5 Check for rpcuser/rpcpassword first then for cookie (Andrew Chow)
3ec5ad8 Add test for rpcuser/rpcpassword (Andrew Chow)
c53c983 Replace cookie auth in tests (Andrew Chow)

Tree-SHA512: 21efb84c87080a895cac8a7fe4766738c34eebe9686c7d10af1bf91ed4ae422e2d5dbbebffd00d34744eb6bb2d0195ea3aca86deebf085bbdeeb1d8b474241ed
This commit is contained in:
Wladimir J. van der Laan 2017-06-21 14:26:10 +02:00
commit d083bd9b9c
No known key found for this signature in database
GPG Key ID: 1E4AED62986CD25D
6 changed files with 97 additions and 30 deletions

View File

@ -16,16 +16,21 @@ class HTTPBasicsTest (BitcoinTestFramework):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.setup_clean_chain = False self.setup_clean_chain = False
self.num_nodes = 1 self.num_nodes = 2
def setup_chain(self): def setup_chain(self):
super().setup_chain() super().setup_chain()
#Append rpcauth to bitcoin.conf before initialization #Append rpcauth to bitcoin.conf before initialization
rpcauth = "rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144" rpcauth = "rpcauth=rt:93648e835a54c573682c2eb19f882535$7681e9c5b74bdd85e78166031d2058e1069b3ed7ed967c93fc63abba06f31144"
rpcauth2 = "rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e" rpcauth2 = "rpcauth=rt2:f8607b1a88861fac29dfccf9b52ff9f$ff36a0c23c8c62b4846112e50fa888416e94c17bfd4c42f88fd8f55ec6a3137e"
rpcuser = "rpcuser=rpcuser💻"
rpcpassword = "rpcpassword=rpcpassword🔑"
with open(os.path.join(self.options.tmpdir+"/node0", "bitcoin.conf"), 'a', encoding='utf8') as f: with open(os.path.join(self.options.tmpdir+"/node0", "bitcoin.conf"), 'a', encoding='utf8') as f:
f.write(rpcauth+"\n") f.write(rpcauth+"\n")
f.write(rpcauth2+"\n") f.write(rpcauth2+"\n")
with open(os.path.join(self.options.tmpdir+"/node1", "bitcoin.conf"), 'a', encoding='utf8') as f:
f.write(rpcuser+"\n")
f.write(rpcpassword+"\n")
def run_test(self): def run_test(self):
@ -50,7 +55,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect() conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse() resp = conn.getresponse()
assert_equal(resp.status==401, False) assert_equal(resp.status, 200)
conn.close() conn.close()
#Use new authpair to confirm both work #Use new authpair to confirm both work
@ -60,7 +65,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect() conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse() resp = conn.getresponse()
assert_equal(resp.status==401, False) assert_equal(resp.status, 200)
conn.close() conn.close()
#Wrong login name with rt's password #Wrong login name with rt's password
@ -71,7 +76,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect() conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse() resp = conn.getresponse()
assert_equal(resp.status==401, True) assert_equal(resp.status, 401)
conn.close() conn.close()
#Wrong password for rt #Wrong password for rt
@ -82,7 +87,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect() conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse() resp = conn.getresponse()
assert_equal(resp.status==401, True) assert_equal(resp.status, 401)
conn.close() conn.close()
#Correct for rt2 #Correct for rt2
@ -93,7 +98,7 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect() conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse() resp = conn.getresponse()
assert_equal(resp.status==401, False) assert_equal(resp.status, 200)
conn.close() conn.close()
#Wrong password for rt2 #Wrong password for rt2
@ -104,7 +109,46 @@ class HTTPBasicsTest (BitcoinTestFramework):
conn.connect() conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse() resp = conn.getresponse()
assert_equal(resp.status==401, True) assert_equal(resp.status, 401)
conn.close()
###############################################################
# Check correctness of the rpcuser/rpcpassword config options #
###############################################################
url = urllib.parse.urlparse(self.nodes[1].url)
# rpcuser and rpcpassword authpair
rpcuserauthpair = "rpcuser💻:rpcpassword🔑"
headers = {"Authorization": "Basic " + str_to_b64str(rpcuserauthpair)}
conn = http.client.HTTPConnection(url.hostname, url.port)
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse()
assert_equal(resp.status, 200)
conn.close()
#Wrong login name with rpcuser's password
rpcuserauthpair = "rpcuserwrong:rpcpassword"
headers = {"Authorization": "Basic " + str_to_b64str(rpcuserauthpair)}
conn = http.client.HTTPConnection(url.hostname, url.port)
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse()
assert_equal(resp.status, 401)
conn.close()
#Wrong password for rpcuser
rpcuserauthpair = "rpcuser:rpcpasswordwrong"
headers = {"Authorization": "Basic " + str_to_b64str(rpcuserauthpair)}
conn = http.client.HTTPConnection(url.hostname, url.port)
conn.connect()
conn.request('POST', '/', '{"method": "getbestblockhash"}', headers)
resp = conn.getresponse()
assert_equal(resp.status, 401)
conn.close() conn.close()

View File

@ -1486,7 +1486,7 @@ class SegWitTest(BitcoinTestFramework):
# nodes would have stored, this requires special handling. # nodes would have stored, this requires special handling.
# To enable this test, pass --oldbinary=<path-to-pre-segwit-bitcoind> to # To enable this test, pass --oldbinary=<path-to-pre-segwit-bitcoind> to
# the test. # the test.
def test_upgrade_after_activation(self, node, node_id): def test_upgrade_after_activation(self, node_id):
self.log.info("Testing software upgrade after softfork activation") self.log.info("Testing software upgrade after softfork activation")
assert(node_id != 0) # node0 is assumed to be a segwit-active bitcoind assert(node_id != 0) # node0 is assumed to be a segwit-active bitcoind
@ -1502,14 +1502,14 @@ class SegWitTest(BitcoinTestFramework):
sync_blocks(self.nodes) sync_blocks(self.nodes)
# Make sure that this peer thinks segwit has activated. # Make sure that this peer thinks segwit has activated.
assert(get_bip9_status(node, 'segwit')['status'] == "active") assert(get_bip9_status(self.nodes[node_id], 'segwit')['status'] == "active")
# Make sure this peers blocks match those of node0. # Make sure this peers blocks match those of node0.
height = node.getblockcount() height = self.nodes[node_id].getblockcount()
while height >= 0: while height >= 0:
block_hash = node.getblockhash(height) block_hash = self.nodes[node_id].getblockhash(height)
assert_equal(block_hash, self.nodes[0].getblockhash(height)) assert_equal(block_hash, self.nodes[0].getblockhash(height))
assert_equal(self.nodes[0].getblock(block_hash), node.getblock(block_hash)) assert_equal(self.nodes[0].getblock(block_hash), self.nodes[node_id].getblock(block_hash))
height -= 1 height -= 1
@ -1944,7 +1944,7 @@ class SegWitTest(BitcoinTestFramework):
self.test_signature_version_1() self.test_signature_version_1()
self.test_non_standard_witness() self.test_non_standard_witness()
sync_blocks(self.nodes) sync_blocks(self.nodes)
self.test_upgrade_after_activation(self.nodes[2], 2) self.test_upgrade_after_activation(node_id=2)
self.test_witness_sigops() self.test_witness_sigops()

View File

@ -315,7 +315,7 @@ class PruneTest(BitcoinTestFramework):
# check that the pruning node's wallet is still in good shape # check that the pruning node's wallet is still in good shape
self.log.info("Stop and start pruning node to trigger wallet rescan") self.log.info("Stop and start pruning node to trigger wallet rescan")
self.stop_node(2) self.stop_node(2)
self.start_node(2, self.options.tmpdir, ["-prune=550"]) self.nodes[2] = self.start_node(2, self.options.tmpdir, ["-prune=550"])
self.log.info("Success") self.log.info("Success")
# check that wallet loads loads successfully when restarting a pruned node after IBD. # check that wallet loads loads successfully when restarting a pruned node after IBD.
@ -325,7 +325,7 @@ class PruneTest(BitcoinTestFramework):
nds = [self.nodes[0], self.nodes[5]] nds = [self.nodes[0], self.nodes[5]]
sync_blocks(nds, wait=5, timeout=300) sync_blocks(nds, wait=5, timeout=300)
self.stop_node(5) #stop and start to trigger rescan self.stop_node(5) #stop and start to trigger rescan
self.start_node(5, self.options.tmpdir, ["-prune=550"]) self.nodes[5] = self.start_node(5, self.options.tmpdir, ["-prune=550"])
self.log.info("Success") self.log.info("Success")
def run_test(self): def run_test(self):

View File

@ -49,7 +49,7 @@ class RPCBindTest(BitcoinTestFramework):
base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips] base_args = ['-disablewallet', '-nolisten'] + ['-rpcallowip='+x for x in allow_ips]
self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, [base_args]) self.nodes = self.start_nodes(self.num_nodes, self.options.tmpdir, [base_args])
# connect to node through non-loopback interface # connect to node through non-loopback interface
node = get_rpc_proxy(rpc_url(0, "%s:%d" % (rpchost, rpcport)), 0) node = get_rpc_proxy(rpc_url(get_datadir_path(self.options.tmpdir, 0), 0, "%s:%d" % (rpchost, rpcport)), 0)
node.getnetworkinfo() node.getnetworkinfo()
self.stop_nodes() self.stop_nodes()

View File

@ -28,6 +28,7 @@ from .util import (
get_mocktime, get_mocktime,
get_rpc_proxy, get_rpc_proxy,
initialize_datadir, initialize_datadir,
get_datadir_path,
log_filename, log_filename,
p2p_port, p2p_port,
rpc_url, rpc_url,
@ -300,13 +301,13 @@ class BitcoinTestFramework(object):
args.append("-connect=127.0.0.1:" + str(p2p_port(0))) args.append("-connect=127.0.0.1:" + str(p2p_port(0)))
bitcoind_processes[i] = subprocess.Popen(args) bitcoind_processes[i] = subprocess.Popen(args)
self.log.debug("initialize_chain: bitcoind started, waiting for RPC to come up") self.log.debug("initialize_chain: bitcoind started, waiting for RPC to come up")
wait_for_bitcoind_start(bitcoind_processes[i], rpc_url(i), i) wait_for_bitcoind_start(bitcoind_processes[i], datadir, i)
self.log.debug("initialize_chain: RPC successfully started") self.log.debug("initialize_chain: RPC successfully started")
self.nodes = [] self.nodes = []
for i in range(MAX_NODES): for i in range(MAX_NODES):
try: try:
self.nodes.append(get_rpc_proxy(rpc_url(i), i)) self.nodes.append(get_rpc_proxy(rpc_url(get_datadir_path(cachedir, i), i), i))
except: except:
self.log.exception("Error connecting to node %d" % i) self.log.exception("Error connecting to node %d" % i)
sys.exit(1) sys.exit(1)

View File

@ -181,21 +181,40 @@ def initialize_datadir(dirname, n):
datadir = os.path.join(dirname, "node"+str(n)) datadir = os.path.join(dirname, "node"+str(n))
if not os.path.isdir(datadir): if not os.path.isdir(datadir):
os.makedirs(datadir) os.makedirs(datadir)
rpc_u, rpc_p = rpc_auth_pair(n)
with open(os.path.join(datadir, "bitcoin.conf"), 'w', encoding='utf8') as f: with open(os.path.join(datadir, "bitcoin.conf"), 'w', encoding='utf8') as f:
f.write("regtest=1\n") f.write("regtest=1\n")
f.write("rpcuser=" + rpc_u + "\n")
f.write("rpcpassword=" + rpc_p + "\n")
f.write("port="+str(p2p_port(n))+"\n") f.write("port="+str(p2p_port(n))+"\n")
f.write("rpcport="+str(rpc_port(n))+"\n") f.write("rpcport="+str(rpc_port(n))+"\n")
f.write("listenonion=0\n") f.write("listenonion=0\n")
return datadir return datadir
def rpc_auth_pair(n): def get_datadir_path(dirname, n):
return 'rpcuser💻' + str(n), 'rpcpass🔑' + str(n) return os.path.join(dirname, "node"+str(n))
def rpc_url(i, rpchost=None): def get_auth_cookie(datadir, n):
rpc_u, rpc_p = rpc_auth_pair(i) user = None
password = None
if os.path.isfile(os.path.join(datadir, "bitcoin.conf")):
with open(os.path.join(datadir, "bitcoin.conf"), 'r') as f:
for line in f:
if line.startswith("rpcuser="):
assert user is None # Ensure that there is only one rpcuser line
user = line.split("=")[1].strip("\n")
if line.startswith("rpcpassword="):
assert password is None # Ensure that there is only one rpcpassword line
password = line.split("=")[1].strip("\n")
if os.path.isfile(os.path.join(datadir, "regtest", ".cookie")):
with open(os.path.join(datadir, "regtest", ".cookie"), 'r') as f:
userpass = f.read()
split_userpass = userpass.split(':')
user = split_userpass[0]
password = split_userpass[1]
if user is None or password is None:
raise ValueError("No RPC credentials")
return user, password
def rpc_url(datadir, i, rpchost=None):
rpc_u, rpc_p = get_auth_cookie(datadir, i)
host = '127.0.0.1' host = '127.0.0.1'
port = rpc_port(i) port = rpc_port(i)
if rpchost: if rpchost:
@ -206,7 +225,7 @@ def rpc_url(i, rpchost=None):
host = rpchost host = rpchost
return "http://%s:%s@%s:%d" % (rpc_u, rpc_p, host, int(port)) return "http://%s:%s@%s:%d" % (rpc_u, rpc_p, host, int(port))
def wait_for_bitcoind_start(process, url, i): def wait_for_bitcoind_start(process, datadir, i, rpchost=None):
''' '''
Wait for bitcoind to start. This means that RPC is accessible and fully initialized. Wait for bitcoind to start. This means that RPC is accessible and fully initialized.
Raise an exception if bitcoind exits during initialization. Raise an exception if bitcoind exits during initialization.
@ -215,7 +234,8 @@ def wait_for_bitcoind_start(process, url, i):
if process.poll() is not None: if process.poll() is not None:
raise Exception('bitcoind exited with status %i during initialization' % process.returncode) raise Exception('bitcoind exited with status %i during initialization' % process.returncode)
try: try:
rpc = get_rpc_proxy(url, i) # Check if .cookie file to be created
rpc = get_rpc_proxy(rpc_url(datadir, i, rpchost), i)
blocks = rpc.getblockcount() blocks = rpc.getblockcount()
break # break out of loop on success break # break out of loop on success
except IOError as e: except IOError as e:
@ -224,6 +244,9 @@ def wait_for_bitcoind_start(process, url, i):
except JSONRPCException as e: # Initialization phase except JSONRPCException as e: # Initialization phase
if e.error['code'] != -28: # RPC in warmup? if e.error['code'] != -28: # RPC in warmup?
raise # unknown JSON RPC exception raise # unknown JSON RPC exception
except ValueError as e: # cookie file not found and no rpcuser or rpcassword. bitcoind still starting
if "No RPC credentials" not in str(e):
raise
time.sleep(0.25) time.sleep(0.25)
@ -239,10 +262,9 @@ def _start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary
if extra_args is not None: args.extend(extra_args) if extra_args is not None: args.extend(extra_args)
bitcoind_processes[i] = subprocess.Popen(args, stderr=stderr) bitcoind_processes[i] = subprocess.Popen(args, stderr=stderr)
logger.debug("initialize_chain: bitcoind started, waiting for RPC to come up") logger.debug("initialize_chain: bitcoind started, waiting for RPC to come up")
url = rpc_url(i, rpchost) wait_for_bitcoind_start(bitcoind_processes[i], datadir, i, rpchost)
wait_for_bitcoind_start(bitcoind_processes[i], url, i)
logger.debug("initialize_chain: RPC successfully started") logger.debug("initialize_chain: RPC successfully started")
proxy = get_rpc_proxy(url, i, timeout=timewait) proxy = get_rpc_proxy(rpc_url(datadir, i, rpchost), i, timeout=timewait)
if COVERAGE_DIR: if COVERAGE_DIR:
coverage.write_all_rpc_commands(COVERAGE_DIR, proxy) coverage.write_all_rpc_commands(COVERAGE_DIR, proxy)