xrpld
Loading...
Searching...
No Matches
Roles_test.cpp
1#include <test/jtx/Env.h>
2#include <test/jtx/WSClient.h>
3#include <test/jtx/envconfig.h>
4
5#include <xrpl/beast/unit_test/suite.h>
6
7#include <boost/asio/ip/address.hpp>
8#include <boost/system/detail/error_code.hpp>
9
10#include <string>
11#include <unordered_map>
12
13namespace xrpl::test {
14
16{
17 static bool
19 {
20 boost::system::error_code ec;
21 boost::asio::ip::make_address(addr, ec);
22 return !ec.failed();
23 }
24
25 void
27 {
28 testcase("Roles");
29 using namespace test::jtx;
30
31 {
32 Env env(*this);
33
34 BEAST_EXPECT(env.rpc("ping")["result"]["role"] == "admin");
35 BEAST_EXPECT(
36 makeWSClient(env.app().config())->invoke("ping")["result"]["unlimited"].asBool());
37 }
38 {
39 Env env{*this, envconfig(noAdmin)};
40
41 BEAST_EXPECT(!env.rpc("ping")["result"].isMember("role"));
42 auto wsRes = makeWSClient(env.app().config())->invoke("ping")["result"];
43 BEAST_EXPECT(!wsRes.isMember("unlimited") || !wsRes["unlimited"].asBool());
44 }
45 {
46 Env env{*this, envconfig(secureGateway)};
47
48 BEAST_EXPECT(env.rpc("ping")["result"]["role"] == "proxied");
49 BEAST_EXPECT(!env.rpc("ping")["result"].isMember("ip"));
50 auto wsRes = makeWSClient(env.app().config())->invoke("ping")["result"];
51 BEAST_EXPECT(!wsRes.isMember("unlimited") || !wsRes["unlimited"].asBool());
52
54 json::Value rpcRes;
55
56 // IPv4 tests.
57 headers["X-Forwarded-For"] = "12.34.56.78";
58 rpcRes = env.rpc(headers, "ping")["result"];
59 BEAST_EXPECT(rpcRes["role"] == "proxied");
60 BEAST_EXPECT(rpcRes["ip"] == "12.34.56.78");
61 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
62
63 headers["X-Forwarded-For"] = "87.65.43.21, 44.33.22.11";
64 rpcRes = env.rpc(headers, "ping")["result"];
65 BEAST_EXPECT(rpcRes["ip"] == "87.65.43.21");
66 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
67
68 headers["X-Forwarded-For"] = "87.65.43.21:47011, 44.33.22.11";
69 rpcRes = env.rpc(headers, "ping")["result"];
70 BEAST_EXPECT(rpcRes["ip"] == "87.65.43.21");
71 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
72
73 headers = {};
74 headers["Forwarded"] = "for=88.77.66.55";
75 rpcRes = env.rpc(headers, "ping")["result"];
76 BEAST_EXPECT(rpcRes["ip"] == "88.77.66.55");
77 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
78
79 headers["Forwarded"] =
80 "what=where;for=55.66.77.88;for=nobody;"
81 "who=3";
82 rpcRes = env.rpc(headers, "ping")["result"];
83 BEAST_EXPECT(rpcRes["ip"] == "55.66.77.88");
84 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
85
86 headers["Forwarded"] =
87 "what=where; for=55.66.77.88, for=99.00.11.22;"
88 "who=3";
89 rpcRes = env.rpc(headers, "ping")["result"];
90 BEAST_EXPECT(rpcRes["ip"] == "55.66.77.88");
91 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
92
93 headers["Forwarded"] =
94 "what=where; For=99.88.77.66, for=55.66.77.88;"
95 "who=3";
96 rpcRes = env.rpc(headers, "ping")["result"];
97 BEAST_EXPECT(rpcRes["ip"] == "99.88.77.66");
98 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
99
100 headers["Forwarded"] =
101 "what=where; for=\"55.66.77.88:47011\";"
102 "who=3";
103 rpcRes = env.rpc(headers, "ping")["result"];
104 BEAST_EXPECT(rpcRes["ip"] == "55.66.77.88");
105 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
106
107 headers["Forwarded"] =
108 "what=where; For= \" 99.88.77.66 \" ,for=11.22.33.44;"
109 "who=3";
110 rpcRes = env.rpc(headers, "ping")["result"];
111 BEAST_EXPECT(rpcRes["ip"] == "99.88.77.66");
112 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
113
114 wsRes = makeWSClient(env.app().config(), true, 2, headers)->invoke("ping")["result"];
115 BEAST_EXPECT(!wsRes.isMember("unlimited") || !wsRes["unlimited"].asBool());
116
117 std::string const name = "xrposhi";
118 headers["X-User"] = name;
119 rpcRes = env.rpc(headers, "ping")["result"];
120 BEAST_EXPECT(rpcRes["role"] == "identified");
121 BEAST_EXPECT(rpcRes["username"] == name);
122 BEAST_EXPECT(rpcRes["ip"] == "99.88.77.66");
123 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
124 wsRes = makeWSClient(env.app().config(), true, 2, headers)->invoke("ping")["result"];
125 BEAST_EXPECT(wsRes["unlimited"].asBool());
126
127 // IPv6 tests.
128 headers = {};
129 headers["X-Forwarded-For"] = "2001:db8:3333:4444:5555:6666:7777:8888";
130 rpcRes = env.rpc(headers, "ping")["result"];
131 BEAST_EXPECT(rpcRes["role"] == "proxied");
132 BEAST_EXPECT(rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:7777:8888");
133 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
134
135 headers["X-Forwarded-For"] =
136 "2001:db8:3333:4444:5555:6666:7777:9999, a:b:c:d:e:f, "
137 "g:h:i:j:k:l";
138 rpcRes = env.rpc(headers, "ping")["result"];
139 BEAST_EXPECT(rpcRes["role"] == "proxied");
140 BEAST_EXPECT(rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:7777:9999");
141 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
142
143 headers["X-Forwarded-For"] = "[2001:db8:3333:4444:5555:6666:7777:8888]";
144 rpcRes = env.rpc(headers, "ping")["result"];
145 BEAST_EXPECT(rpcRes["role"] == "proxied");
146 BEAST_EXPECT(rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:7777:8888");
147 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
148
149 headers["X-Forwarded-For"] =
150 "[2001:db8:3333:4444:5555:6666:7777:9999], [a:b:c:d:e:f], "
151 "[g:h:i:j:k:l]";
152 rpcRes = env.rpc(headers, "ping")["result"];
153 BEAST_EXPECT(rpcRes["role"] == "proxied");
154 BEAST_EXPECT(rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:7777:9999");
155 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
156
157 headers = {};
158 headers["Forwarded"] = "for=\"[2001:db8:3333:4444:5555:6666:7777:aaaa]\"";
159 rpcRes = env.rpc(headers, "ping")["result"];
160 BEAST_EXPECT(rpcRes["role"] == "proxied");
161 BEAST_EXPECT(rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:7777:aaaa");
162 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
163
164 headers["Forwarded"] = "For=\"[2001:db8:bb:cc:dd:ee:ff::]:2345\", for=99.00.11.22";
165 rpcRes = env.rpc(headers, "ping")["result"];
166 BEAST_EXPECT(rpcRes["role"] == "proxied");
167 BEAST_EXPECT(rpcRes["ip"] == "2001:db8:bb:cc:dd:ee:ff::");
168 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
169
170 headers["Forwarded"] =
171 "proto=http;FOR=\"[2001:db8:11:22:33:44:55:66]\""
172 ";by=203.0.113.43";
173 rpcRes = env.rpc(headers, "ping")["result"];
174 BEAST_EXPECT(rpcRes["role"] == "proxied");
175 BEAST_EXPECT(rpcRes["ip"] == "2001:db8:11:22:33:44:55:66");
176 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
177
178 // IPv6 (dual) tests.
179 headers = {};
180 headers["X-Forwarded-For"] = "2001:db8:3333:4444:5555:6666:1.2.3.4";
181 rpcRes = env.rpc(headers, "ping")["result"];
182 BEAST_EXPECT(rpcRes["role"] == "proxied");
183 BEAST_EXPECT(rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:1.2.3.4");
184 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
185
186 headers["X-Forwarded-For"] =
187 "2001:db8:3333:4444:5555:6666:5.6.7.8, a:b:c:d:e:f, "
188 "g:h:i:j:k:l";
189 rpcRes = env.rpc(headers, "ping")["result"];
190 BEAST_EXPECT(rpcRes["role"] == "proxied");
191 BEAST_EXPECT(rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:5.6.7.8");
192 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
193
194 headers["X-Forwarded-For"] = "[2001:db8:3333:4444:5555:6666:9.10.11.12]";
195 rpcRes = env.rpc(headers, "ping")["result"];
196 BEAST_EXPECT(rpcRes["role"] == "proxied");
197 BEAST_EXPECT(rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:9.10.11.12");
198 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
199
200 headers["X-Forwarded-For"] =
201 "[2001:db8:3333:4444:5555:6666:13.14.15.16], [a:b:c:d:e:f], "
202 "[g:h:i:j:k:l]";
203 rpcRes = env.rpc(headers, "ping")["result"];
204 BEAST_EXPECT(rpcRes["role"] == "proxied");
205 BEAST_EXPECT(rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:13.14.15.16");
206 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
207
208 headers = {};
209 headers["Forwarded"] = "for=\"[2001:db8:3333:4444:5555:6666:20.19.18.17]\"";
210 rpcRes = env.rpc(headers, "ping")["result"];
211 BEAST_EXPECT(rpcRes["role"] == "proxied");
212 BEAST_EXPECT(rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:20.19.18.17");
213 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
214
215 headers["Forwarded"] = "For=\"[2001:db8:bb:cc::24.23.22.21]\", for=99.00.11.22";
216 rpcRes = env.rpc(headers, "ping")["result"];
217 BEAST_EXPECT(rpcRes["role"] == "proxied");
218 BEAST_EXPECT(rpcRes["ip"] == "2001:db8:bb:cc::24.23.22.21");
219 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
220
221 headers["Forwarded"] =
222 "proto=http;FOR=\"[::11:22:33:44:45.55.65.75]:234\""
223 ";by=203.0.113.43";
224 rpcRes = env.rpc(headers, "ping")["result"];
225 BEAST_EXPECT(rpcRes["role"] == "proxied");
226 BEAST_EXPECT(rpcRes["ip"] == "::11:22:33:44:45.55.65.75");
227 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
228
229 // Test: "for=" not at the beginning AND no trailing delimiter.
230 // This exercises the fix for the buffer over-read bug where
231 // the remaining length was incorrectly calculated.
232 headers["Forwarded"] = "by=203.0.113.43;for=1.2.3.4";
233 rpcRes = env.rpc(headers, "ping")["result"];
234 BEAST_EXPECT(rpcRes["role"] == "proxied");
235 BEAST_EXPECT(rpcRes["ip"] == "1.2.3.4");
236 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
237
238 headers["Forwarded"] = "proto=https;by=proxy.example.com;for=5.6.7.8";
239 rpcRes = env.rpc(headers, "ping")["result"];
240 BEAST_EXPECT(rpcRes["role"] == "proxied");
241 BEAST_EXPECT(rpcRes["ip"] == "5.6.7.8");
242 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
243 }
244
245 {
246 Env env{*this, envconfig(adminLocalnet)};
247 BEAST_EXPECT(env.rpc("ping")["result"]["role"] == "admin");
248 BEAST_EXPECT(
249 makeWSClient(env.app().config())->invoke("ping")["result"]["unlimited"].asBool());
250 }
251
252 {
254 BEAST_EXPECT(env.rpc("ping")["result"]["role"] == "proxied");
255 auto wsRes = makeWSClient(env.app().config())->invoke("ping")["result"];
256 BEAST_EXPECT(!wsRes.isMember("unlimited") || !wsRes["unlimited"].asBool());
257
259 headers["X-Forwarded-For"] = "12.34.56.78";
260 json::Value rpcRes = env.rpc(headers, "ping")["result"];
261 BEAST_EXPECT(rpcRes["role"] == "proxied");
262 BEAST_EXPECT(rpcRes["ip"] == "12.34.56.78");
263 BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
264 }
265 }
266
267 void
269 {
270 using namespace test::jtx;
271 testcase("Invalid IP addresses");
272
273 {
274 Env env(*this);
275
277 json::Value rpcRes;
278
279 // No "for=" in Forwarded.
280 headers["Forwarded"] = "for 88.77.66.55";
281 rpcRes = env.rpc(headers, "ping")["result"];
282 BEAST_EXPECT(rpcRes["role"] == "admin");
283 BEAST_EXPECT(!rpcRes.isMember("ip"));
284
285 headers["Forwarded"] = "by=88.77.66.55";
286 rpcRes = env.rpc(headers, "ping")["result"];
287 BEAST_EXPECT(rpcRes["role"] == "admin");
288 BEAST_EXPECT(!rpcRes.isMember("ip"));
289
290 // Empty field.
291 headers = {};
292 headers["Forwarded"] = "for=";
293 rpcRes = env.rpc(headers, "ping")["result"];
294 BEAST_EXPECT(rpcRes["role"] == "admin");
295 BEAST_EXPECT(!rpcRes.isMember("ip"));
296
297 headers = {};
298 headers["X-Forwarded-For"] = " ";
299 rpcRes = env.rpc(headers, "ping")["result"];
300 BEAST_EXPECT(rpcRes["role"] == "admin");
301 BEAST_EXPECT(!rpcRes.isMember("ip"));
302
303 // Empty quotes.
304 headers = {};
305 headers["Forwarded"] = "for= \" \" ";
306 rpcRes = env.rpc(headers, "ping")["result"];
307 BEAST_EXPECT(rpcRes["role"] == "admin");
308 BEAST_EXPECT(!rpcRes.isMember("ip"));
309
310 headers = {};
311 headers["X-Forwarded-For"] = "\"\"";
312 rpcRes = env.rpc(headers, "ping")["result"];
313 BEAST_EXPECT(rpcRes["role"] == "admin");
314 BEAST_EXPECT(!rpcRes.isMember("ip"));
315
316 // Unbalanced outer quotes.
317 headers = {};
318 headers["X-Forwarded-For"] = "\"12.34.56.78 ";
319 rpcRes = env.rpc(headers, "ping")["result"];
320 BEAST_EXPECT(rpcRes["role"] == "admin");
321 BEAST_EXPECT(!rpcRes.isMember("ip"));
322
323 headers["X-Forwarded-For"] = "12.34.56.78\"";
324 rpcRes = env.rpc(headers, "ping")["result"];
325 BEAST_EXPECT(rpcRes["role"] == "admin");
326 BEAST_EXPECT(!rpcRes.isMember("ip"));
327
328 // Unbalanced square brackets for IPv6.
329 headers = {};
330 headers["Forwarded"] = "FOR=[2001:db8:bb:cc::";
331 rpcRes = env.rpc(headers, "ping")["result"];
332 BEAST_EXPECT(rpcRes["role"] == "admin");
333 BEAST_EXPECT(!rpcRes.isMember("ip"));
334
335 headers = {};
336 headers["X-Forwarded-For"] = "2001:db8:bb:cc::24.23.22.21]";
337 rpcRes = env.rpc(headers, "ping")["result"];
338 BEAST_EXPECT(rpcRes["role"] == "admin");
339 BEAST_EXPECT(!rpcRes.isMember("ip"));
340
341 // Empty square brackets.
342 headers = {};
343 headers["Forwarded"] = "FOR=[]";
344 rpcRes = env.rpc(headers, "ping")["result"];
345 BEAST_EXPECT(rpcRes["role"] == "admin");
346 BEAST_EXPECT(!rpcRes.isMember("ip"));
347
348 headers = {};
349 headers["X-Forwarded-For"] = "\" [ ] \"";
350 rpcRes = env.rpc(headers, "ping")["result"];
351 BEAST_EXPECT(rpcRes["role"] == "admin");
352 BEAST_EXPECT(!rpcRes.isMember("ip"));
353 }
354 }
355
356public:
357 void
358 run() override
359 {
360 testRoles();
362 }
363};
364
366
367} // namespace xrpl::test
A testsuite class.
Definition suite.h:50
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:149
Represents a JSON value.
Definition json_value.h:130
bool isMember(char const *key) const
Return true if the object has a member named key.
virtual Config & config()=0
static bool isValidIpAddress(std::string const &addr)
void run() override
Runs the suite.
A transaction testing environment.
Definition Env.h:143
Application & app()
Definition Env.h:280
json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition Env.h:864
std::unique_ptr< Config > secureGateway(std::unique_ptr< Config >)
Definition envconfig.cpp:72
std::unique_ptr< Config > secureGatewayLocalnet(std::unique_ptr< Config >)
Definition envconfig.cpp:89
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition envconfig.h:28
std::unique_ptr< Config > adminLocalnet(std::unique_ptr< Config >)
Definition envconfig.cpp:81
std::unique_ptr< Config > noAdmin(std::unique_ptr< Config >)
adjust config so no admin ports are enabled
Definition envconfig.cpp:64
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
std::unique_ptr< WSClient > makeWSClient(Config const &cfg, bool v2, unsigned rpcVersion, std::unordered_map< std::string, std::string > const &headers)
Returns a client operating through WebSockets/S.
Definition WSClient.cpp:329
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5