Skip to content

Commit 7330982

Browse files
Merge dashpay#6100: feat: make whitelist works with composite commands for platform needs
85abbb9 chore: add release notes for composite command for whitelist (Konstantin Akimov) 78ad778 feat: test composite commands in functional test for whitelist (Konstantin Akimov) a102a59 feat: add support of composite commands in RPC'c whitelists (Konstantin Akimov) Pull request description: ## Issue being fixed or feature implemented dashpay/dash-issues#66 dashpay/dash-issues#65 ## What was done? Our composite commands such as "quorum list" have been refactored to make them truly compatible with other features, such as whitelist, see dashpay#6052 dashpay#6051 dashpay#6055 and other related PRs This PR makes whitelist feature to be compatible with composite commands. Instead implementing additional users such "dapi" better to provide universal way which do not require new build for every new API that has been used by platform, let's simplify things. Platform at their side can use config such as this one (created based on shumkov's example): ``` rpc: { host: '127.0.0.1', port: 9998, users: [ { user: 'dashmate', password: 'rpcpassword', whitelist: null, lowPriority: false, }, { username: 'platform-dapi', password: 'rpcpassword', whitelist: [], lowPriority: true, }, { username: 'platform-drive-consensus', password: 'rpcpassword', whitelist: [getbestchainlock,getblockchaininfo,getrawtransaction,submitchainlock,verifychainlock,protx_listdiff,quorum_listextended,quorum_info,getassetunlockstatuses,sendrawtransaction,mnsync_status] lowPriority: false, }, { username: 'platform-drive-other', password: 'rpcpassword', whitelist: [getbestchainlock,getblockchaininfo,getrawtransaction,submitchainlock,verifychainlock,protx_listdiff,quorum_listextended,quorum_info,getassetunlockstatuses,sendrawtransaction,mnsync_status] ], lowPriority: true, }, ], allowIps: ['127.0.0.1', '172.16.0.0/12', '192.168.0.0/16'], }, ``` ## How Has This Been Tested? Updated functional tests, see commits ## Breaking Changes n/a ## Checklist: - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation - [x] I have assigned this pull request to a milestone ACKs for top commit: UdjinM6: LGTM, utACK 85abbb9 PastaPastaPasta: utACK 85abbb9 Tree-SHA512: 88608179c347420269880c352cf9f3b46272f3fc62e8e7158042e53ad69dc460d5210a1f89e1e09081d090250c87fcececade88e2ddec09f73f1175836d7867b
1 parent 9998ffd commit 7330982

File tree

3 files changed

+38
-5
lines changed

3 files changed

+38
-5
lines changed

doc/release-notes-6100.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
## Remote Procedure Call (RPC) Changes
2+
3+
### Improved support of composite commands
4+
5+
Dash Core's composite commands such as `quorum list` or `bls generate` now are compatible with a whitelist feature.
6+
7+
For example, whitelist `getblockcount,quorumlist` will let to call commands `getblockcount`, `quorum list`, but not `quorum sign`
8+
9+
Note, that adding simple `quorum` in whitelist will allow to use all kind of `quorum...` commands, such as `quorum`, `quorum list`, `quorum sign`, etc

src/httprpc.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,17 @@ class RpcHttpRequest
101101
}
102102
};
103103

104+
static bool whitelisted(JSONRPCRequest jreq)
105+
{
106+
if (g_rpc_whitelist[jreq.authUser].count(jreq.strMethod)) return true;
107+
108+
// check for composite command after
109+
if (!jreq.params.isArray() || jreq.params.empty()) return false;
110+
if (!jreq.params[0].isStr()) return false;
111+
112+
return g_rpc_whitelist[jreq.authUser].count(jreq.strMethod + jreq.params[0].get_str());
113+
}
114+
104115
static bool JSONErrorReply(RpcHttpRequest& rpcRequest, const UniValue& objError, const UniValue& id)
105116
{
106117
// Send error reply from json-rpc error object
@@ -226,7 +237,7 @@ static bool HTTPReq_JSONRPC(const CoreContext& context, HTTPRequest* req)
226237
jreq.parse(valRequest);
227238
rpcRequest.command = jreq.strMethod;
228239

229-
if (user_has_whitelist && !g_rpc_whitelist[jreq.authUser].count(jreq.strMethod)) {
240+
if (user_has_whitelist && !whitelisted(jreq)) {
230241
LogPrintf("RPC User %s not allowed to call method %s\n", jreq.authUser, jreq.strMethod);
231242
return rpcRequest.send_reply(HTTP_FORBIDDEN);
232243
}
@@ -245,7 +256,7 @@ static bool HTTPReq_JSONRPC(const CoreContext& context, HTTPRequest* req)
245256
const UniValue& request = valRequest[reqIdx].get_obj();
246257
// Parse method
247258
std::string strMethod = find_value(request, "method").get_str();
248-
if (!g_rpc_whitelist[jreq.authUser].count(strMethod)) {
259+
if (!whitelisted(jreq)) {
249260
LogPrintf("RPC User %s not allowed to call method %s\n", jreq.authUser, strMethod);
250261
return rpcRequest.send_reply(HTTP_FORBIDDEN);
251262
}

test/functional/rpc_whitelist.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,27 @@
1212
assert_equal,
1313
str_to_b64str
1414
)
15+
import json
1516
import http.client
17+
import re
1618
import urllib.parse
1719

1820
def rpccall(node, user, method):
1921
url = urllib.parse.urlparse(node.url)
2022
headers = {"Authorization": "Basic " + str_to_b64str('{}:{}'.format(user[0], user[3]))}
2123
conn = http.client.HTTPConnection(url.hostname, url.port)
2224
conn.connect()
23-
conn.request('POST', '/', '{"method": "' + method + '"}', headers)
25+
26+
# composite commands are presented without space in whitelist
27+
# but space can't be ommitted when using CLI/http rpc
28+
# for sack of test, substitute missing space for quorum composite command
29+
params = []
30+
if re.match(r"^quorum[^ ]", method):
31+
params = [method[6:]]
32+
method = "quorum"
33+
query = {"method" : method, "params" : params}
34+
35+
conn.request('POST', '/', json.dumps(query), headers)
2436
resp = conn.getresponse()
2537
conn.close()
2638
return resp
@@ -39,7 +51,8 @@ def setup_chain(self):
3951
# 3 => Password Plaintext
4052
self.users = [
4153
["user1", "50358aa884c841648e0700b073c32b2e$b73e95fff0748cc0b517859d2ca47d9bac1aa78231f3e48fa9222b612bd2083e", "getbestblockhash,getblockcount,", "12345"],
42-
["user2", "8650ba41296f62092377a38547f361de$4620db7ba063ef4e2f7249853e9f3c5c3592a9619a759e3e6f1c63f2e22f1d21", "getblockcount", "54321"]
54+
["user2", "8650ba41296f62092377a38547f361de$4620db7ba063ef4e2f7249853e9f3c5c3592a9619a759e3e6f1c63f2e22f1d21", "getblockcount", "54321"],
55+
["platform-user", "8650ba41296f62092377a38547f361de$4620db7ba063ef4e2f7249853e9f3c5c3592a9619a759e3e6f1c63f2e22f1d21", "getblockcount,quorumlist", "54321"],
4356
]
4457
# For exceptions
4558
self.strange_users = [
@@ -55,7 +68,7 @@ def setup_chain(self):
5568
["strangedude5", "d12c6e962d47a454f962eb41225e6ec8$2dd39635b155536d3c1a2e95d05feff87d5ba55f2d5ff975e6e997a836b717c9", ":getblockcount,getblockcount", "s7R4nG3R7H1nGZ"]
5669
]
5770
# These commands shouldn't be allowed for any user to test failures
58-
self.never_allowed = ["getnetworkinfo"]
71+
self.never_allowed = ["getnetworkinfo", "quorum sign"]
5972
with open(os.path.join(get_datadir_path(self.options.tmpdir, 0), "dash.conf"), 'a', encoding='utf8') as f:
6073
f.write("\nrpcwhitelistdefault=0\n")
6174
for user in self.users:

0 commit comments

Comments
 (0)