rpc_whitelist.py raw

   1  #!/usr/bin/env python3
   2  # Copyright (c) 2017-present The Bitcoin Core developers
   3  # Distributed under the MIT software license, see the accompanying
   4  # file COPYING or http://www.opensource.org/licenses/mit-license.php.
   5  """
   6  A test for RPC users with restricted permissions
   7  """
   8  from test_framework.test_framework import BitcoinTestFramework
   9  from test_framework.util import (
  10      assert_equal,
  11      str_to_b64str,
  12  )
  13  import http.client
  14  import urllib.parse
  15  
  16  
  17  def rpccall(node, user, method):
  18      url = urllib.parse.urlparse(node.url)
  19      headers = {"Authorization": "Basic " + str_to_b64str('{}:{}'.format(user[0], user[3]))}
  20      conn = http.client.HTTPConnection(url.hostname, url.port)
  21      conn.connect()
  22      conn.request('POST', '/', '{"method": "' + method + '"}', headers)
  23      resp = conn.getresponse()
  24      conn.close()
  25      return resp
  26  
  27  
  28  def get_permissions(whitelist):
  29      return [perm for perm in whitelist.split(",") if perm]
  30  
  31  
  32  class RPCWhitelistTest(BitcoinTestFramework):
  33  
  34      def set_test_params(self):
  35          self.num_nodes = 1
  36  
  37      def run_test(self):
  38          # 0 => Username
  39          # 1 => Password (Hashed)
  40          # 2 => Permissions
  41          # 3 => Password Plaintext
  42          self.users = [
  43              ["user1", "50358aa884c841648e0700b073c32b2e$b73e95fff0748cc0b517859d2ca47d9bac1aa78231f3e48fa9222b612bd2083e", "getbestblockhash,getblockcount,", "12345"],
  44              ["user2", "8650ba41296f62092377a38547f361de$4620db7ba063ef4e2f7249853e9f3c5c3592a9619a759e3e6f1c63f2e22f1d21", "getblockcount", "54321"]
  45          ]
  46          # For exceptions
  47          self.strange_users = [
  48              # Test empty
  49              ["strangedude", "62d67dffec03836edd698314f1b2be62$c2fb4be29bb0e3646298661123cf2d8629640979cabc268ef05ea613ab54068d", ":", "s7R4nG3R7H1nGZ"],
  50              ["strangedude2", "575c012c7fe4b1e83b9d809412da3ef7$09f448d0acfc19924dd62ecb96004d3c2d4b91f471030dfe43c6ea64a8f658c1", "", "s7R4nG3R7H1nGZ"],
  51              # Test trailing comma
  52              ["strangedude3", "23189c561b5975a56f4cf94030495d61$3a2f6aac26351e2257428550a553c4c1979594e36675bbd3db692442387728c0", ":getblockcount,", "s7R4nG3R7H1nGZ"],
  53              # Test overwrite
  54              ["strangedude4", "990c895760a70df83949e8278665e19a$8f0906f20431ff24cb9e7f5b5041e4943bdf2a5c02a19ef4960dcf45e72cde1c", ":getblockcount, getbestblockhash", "s7R4nG3R7H1nGZ"],
  55              ["strangedude4", "990c895760a70df83949e8278665e19a$8f0906f20431ff24cb9e7f5b5041e4943bdf2a5c02a19ef4960dcf45e72cde1c", ":getblockcount", "s7R4nG3R7H1nGZ"],
  56              # Testing the same permission twice
  57              ["strangedude5", "d12c6e962d47a454f962eb41225e6ec8$2dd39635b155536d3c1a2e95d05feff87d5ba55f2d5ff975e6e997a836b717c9", ":getblockcount,getblockcount", "s7R4nG3R7H1nGZ"],
  58              # Test non-whitelisted user
  59              ["strangedude6", "67e5583538958883291f6917883eca64$8a866953ef9c5b7d078a62c64754a4eb74f47c2c17821eb4237021d7ef44f991", None, "N4SziYbHmhC1"]
  60          ]
  61          # These commands shouldn't be allowed for any user to test failures
  62          self.never_allowed = ["getnetworkinfo"]
  63          with open(self.nodes[0].datadir_path / "bitcoin.conf", "a") as f:
  64              f.write("\nrpcwhitelistdefault=0\n")
  65              for user in self.users:
  66                  f.write("rpcauth=" + user[0] + ":" + user[1] + "\n")
  67                  f.write("rpcwhitelist=" + user[0] + ":" + user[2] + "\n")
  68              # Special cases
  69              for strangedude in self.strange_users:
  70                  f.write("rpcauth=" + strangedude[0] + ":" + strangedude[1] + "\n")
  71                  if strangedude[2] is not None:
  72                      f.write("rpcwhitelist=" + strangedude[0] + strangedude[2] + "\n")
  73          self.restart_node(0)
  74  
  75          for user in self.users:
  76              for permission in self.never_allowed:
  77                  self.log.info(f"[{user[0]}]: Testing a non permitted permission ({permission})")
  78                  assert_equal(403, rpccall(self.nodes[0], user, permission).status)
  79          # Now test the strange users
  80          for permission in self.never_allowed:
  81              self.log.info("Strange test 1")
  82              assert_equal(403, rpccall(self.nodes[0], self.strange_users[0], permission).status)
  83          for permission in self.never_allowed:
  84              self.log.info("Strange test 2")
  85              assert_equal(403, rpccall(self.nodes[0], self.strange_users[1], permission).status)
  86          self.log.info("Strange test 3")
  87          assert_equal(200, rpccall(self.nodes[0], self.strange_users[2], "getblockcount").status)
  88          self.log.info("Strange test 4")
  89          assert_equal(403, rpccall(self.nodes[0], self.strange_users[3], "getbestblockhash").status)
  90          self.log.info("Strange test 5")
  91          assert_equal(200, rpccall(self.nodes[0], self.strange_users[4], "getblockcount").status)
  92  
  93          self.test_users_permissions()
  94          self.test_rpcwhitelistdefault_permissions(0, 200)
  95  
  96          # Replace file configurations
  97          self.nodes[0].replace_in_config([("rpcwhitelistdefault=0", "rpcwhitelistdefault=1")])
  98          with open(self.nodes[0].datadir_path / "bitcoin.conf", 'a') as f:
  99              f.write("rpcwhitelist=__cookie__:getblockcount,getblockchaininfo,getmempoolinfo,stop\n")
 100          self.restart_node(0)
 101  
 102          self.test_users_permissions()
 103          self.test_rpcwhitelistdefault_permissions(1, 403)
 104  
 105          # Ensure that not specifying -rpcwhitelistdefault is the same as
 106          # specifying -rpcwhitelistdefault=1. Only explicitly whitelisted users
 107          # should be allowed.
 108          self.nodes[0].replace_in_config([("rpcwhitelistdefault=1", "")])
 109          self.restart_node(0)
 110          self.test_users_permissions()
 111          self.test_rpcwhitelistdefault_permissions(1, 403)
 112  
 113      def test_users_permissions(self):
 114          """
 115          * Permissions:
 116              (user1): getbestblockhash,getblockcount
 117              (user2): getblockcount
 118          Expected result:  * users can only access whitelisted methods
 119          """
 120          for user in self.users:
 121              permissions = get_permissions(user[2])
 122              for permission in permissions:
 123                  self.log.info(f"[{user[0]}]: Testing whitelisted user permission ({permission})")
 124                  assert_equal(200, rpccall(self.nodes[0], user, permission).status)
 125              self.log.info(f"[{user[0]}]: Testing non-permitted permission: getblockchaininfo")
 126              assert_equal(403, rpccall(self.nodes[0], user, "getblockchaininfo").status)
 127  
 128      def test_rpcwhitelistdefault_permissions(self, default_value, expected_status):
 129          """
 130          * rpcwhitelistdefault={default_value}
 131          * No Permissions defined
 132          Expected result: strangedude6 (not whitelisted) access is determined by default_value
 133          When default_value=0: expects 200
 134          When default_value=1: expects 403
 135          """
 136          user = self.strange_users[6]  # strangedude6
 137          for permission in ["getbestblockhash", "getblockchaininfo"]:
 138              self.log.info(f"[{user[0]}]: Testing rpcwhitelistdefault={default_value} no specified permission ({permission})")
 139              assert_equal(expected_status, rpccall(self.nodes[0], user, permission).status)
 140  
 141  
 142  if __name__ == "__main__":
 143      RPCWhitelistTest(__file__).main()
 144