rippled
Roles_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2019 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/beast/unit_test.h>
21 #include <ripple/protocol/ErrorCodes.h>
22 #include <ripple/protocol/jss.h>
23 #include <test/jtx.h>
24 #include <test/jtx/WSClient.h>
25 
26 #include <boost/asio/ip/address_v4.hpp>
27 
28 #include <string>
29 #include <unordered_map>
30 
31 namespace ripple {
32 
33 namespace test {
34 
35 class Roles_test : public beast::unit_test::suite
36 {
37  bool
39  {
40  boost::system::error_code ec;
41  boost::asio::ip::make_address(addr, ec);
42  return !ec.failed();
43  }
44 
45  void
47  {
48  using namespace test::jtx;
49 
50  {
51  Env env(*this);
52 
53  BEAST_EXPECT(env.rpc("ping")["result"]["role"] == "admin");
54  BEAST_EXPECT(makeWSClient(env.app().config())
55  ->invoke("ping")["result"]["unlimited"]
56  .asBool());
57  }
58  {
59  Env env{*this, envconfig(no_admin)};
60 
61  BEAST_EXPECT(!env.rpc("ping")["result"].isMember("role"));
62  auto wsRes =
63  makeWSClient(env.app().config())->invoke("ping")["result"];
64  BEAST_EXPECT(
65  !wsRes.isMember("unlimited") || !wsRes["unlimited"].asBool());
66  }
67  {
68  Env env{*this, envconfig(secure_gateway)};
69 
70  BEAST_EXPECT(env.rpc("ping")["result"]["role"] == "proxied");
71  auto wsRes =
72  makeWSClient(env.app().config())->invoke("ping")["result"];
73  BEAST_EXPECT(
74  !wsRes.isMember("unlimited") || !wsRes["unlimited"].asBool());
75 
77  Json::Value rpcRes;
78 
79  // IPv4 tests.
80  headers["X-Forwarded-For"] = "12.34.56.78";
81  rpcRes = env.rpc(headers, "ping")["result"];
82  BEAST_EXPECT(rpcRes["role"] == "proxied");
83  BEAST_EXPECT(rpcRes["ip"] == "12.34.56.78");
84  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
85 
86  headers["X-Forwarded-For"] = "87.65.43.21, 44.33.22.11";
87  rpcRes = env.rpc(headers, "ping")["result"];
88  BEAST_EXPECT(rpcRes["ip"] == "87.65.43.21");
89  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
90 
91  headers["X-Forwarded-For"] = "87.65.43.21:47011, 44.33.22.11";
92  rpcRes = env.rpc(headers, "ping")["result"];
93  BEAST_EXPECT(rpcRes["ip"] == "87.65.43.21");
94  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
95 
96  headers = {};
97  headers["Forwarded"] = "for=88.77.66.55";
98  rpcRes = env.rpc(headers, "ping")["result"];
99  BEAST_EXPECT(rpcRes["ip"] == "88.77.66.55");
100  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
101 
102  headers["Forwarded"] =
103  "what=where;for=55.66.77.88;for=nobody;"
104  "who=3";
105  rpcRes = env.rpc(headers, "ping")["result"];
106  BEAST_EXPECT(rpcRes["ip"] == "55.66.77.88");
107  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
108 
109  headers["Forwarded"] =
110  "what=where; for=55.66.77.88, for=99.00.11.22;"
111  "who=3";
112  rpcRes = env.rpc(headers, "ping")["result"];
113  BEAST_EXPECT(rpcRes["ip"] == "55.66.77.88");
114  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
115 
116  headers["Forwarded"] =
117  "what=where; For=99.88.77.66, for=55.66.77.88;"
118  "who=3";
119  rpcRes = env.rpc(headers, "ping")["result"];
120  BEAST_EXPECT(rpcRes["ip"] == "99.88.77.66");
121  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
122 
123  headers["Forwarded"] =
124  "what=where; for=\"55.66.77.88:47011\";"
125  "who=3";
126  rpcRes = env.rpc(headers, "ping")["result"];
127  BEAST_EXPECT(rpcRes["ip"] == "55.66.77.88");
128  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
129 
130  headers["Forwarded"] =
131  "what=where; For= \" 99.88.77.66 \" ,for=11.22.33.44;"
132  "who=3";
133  rpcRes = env.rpc(headers, "ping")["result"];
134  BEAST_EXPECT(rpcRes["ip"] == "99.88.77.66");
135  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
136 
137  wsRes = makeWSClient(env.app().config(), true, 2, headers)
138  ->invoke("ping")["result"];
139  BEAST_EXPECT(
140  !wsRes.isMember("unlimited") || !wsRes["unlimited"].asBool());
141 
142  std::string const name = "xrposhi";
143  headers["X-User"] = name;
144  rpcRes = env.rpc(headers, "ping")["result"];
145  BEAST_EXPECT(rpcRes["role"] == "identified");
146  BEAST_EXPECT(rpcRes["username"] == name);
147  BEAST_EXPECT(rpcRes["ip"] == "99.88.77.66");
148  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
149  wsRes = makeWSClient(env.app().config(), true, 2, headers)
150  ->invoke("ping")["result"];
151  BEAST_EXPECT(wsRes["unlimited"].asBool());
152 
153  // IPv6 tests.
154  headers = {};
155  headers["X-Forwarded-For"] =
156  "2001:db8:3333:4444:5555:6666:7777:8888";
157  rpcRes = env.rpc(headers, "ping")["result"];
158  BEAST_EXPECT(rpcRes["role"] == "proxied");
159  BEAST_EXPECT(
160  rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:7777:8888");
161  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
162 
163  headers["X-Forwarded-For"] =
164  "2001:db8:3333:4444:5555:6666:7777:9999, a:b:c:d:e:f, "
165  "g:h:i:j:k:l";
166  rpcRes = env.rpc(headers, "ping")["result"];
167  BEAST_EXPECT(rpcRes["role"] == "proxied");
168  BEAST_EXPECT(
169  rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:7777:9999");
170  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
171 
172  headers["X-Forwarded-For"] =
173  "[2001:db8:3333:4444:5555:6666:7777:8888]";
174  rpcRes = env.rpc(headers, "ping")["result"];
175  BEAST_EXPECT(rpcRes["role"] == "proxied");
176  BEAST_EXPECT(
177  rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:7777:8888");
178  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
179 
180  headers["X-Forwarded-For"] =
181  "[2001:db8:3333:4444:5555:6666:7777:9999], [a:b:c:d:e:f], "
182  "[g:h:i:j:k:l]";
183  rpcRes = env.rpc(headers, "ping")["result"];
184  BEAST_EXPECT(rpcRes["role"] == "proxied");
185  BEAST_EXPECT(
186  rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:7777:9999");
187  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
188 
189  headers = {};
190  headers["Forwarded"] =
191  "for=\"[2001:db8:3333:4444:5555:6666:7777:aaaa]\"";
192  rpcRes = env.rpc(headers, "ping")["result"];
193  BEAST_EXPECT(rpcRes["role"] == "proxied");
194  BEAST_EXPECT(
195  rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:7777:aaaa");
196  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
197 
198  headers["Forwarded"] =
199  "For=\"[2001:db8:bb:cc:dd:ee:ff::]:2345\", for=99.00.11.22";
200  rpcRes = env.rpc(headers, "ping")["result"];
201  BEAST_EXPECT(rpcRes["role"] == "proxied");
202  BEAST_EXPECT(rpcRes["ip"] == "2001:db8:bb:cc:dd:ee:ff::");
203  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
204 
205  headers["Forwarded"] =
206  "proto=http;FOR=\"[2001:db8:11:22:33:44:55:66]\""
207  ";by=203.0.113.43";
208  rpcRes = env.rpc(headers, "ping")["result"];
209  BEAST_EXPECT(rpcRes["role"] == "proxied");
210  BEAST_EXPECT(rpcRes["ip"] == "2001:db8:11:22:33:44:55:66");
211  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
212 
213  // IPv6 (dual) tests.
214  headers = {};
215  headers["X-Forwarded-For"] = "2001:db8:3333:4444:5555:6666:1.2.3.4";
216  rpcRes = env.rpc(headers, "ping")["result"];
217  BEAST_EXPECT(rpcRes["role"] == "proxied");
218  BEAST_EXPECT(
219  rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:1.2.3.4");
220  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
221 
222  headers["X-Forwarded-For"] =
223  "2001:db8:3333:4444:5555:6666:5.6.7.8, a:b:c:d:e:f, "
224  "g:h:i:j:k:l";
225  rpcRes = env.rpc(headers, "ping")["result"];
226  BEAST_EXPECT(rpcRes["role"] == "proxied");
227  BEAST_EXPECT(
228  rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:5.6.7.8");
229  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
230 
231  headers["X-Forwarded-For"] =
232  "[2001:db8:3333:4444:5555:6666:9.10.11.12]";
233  rpcRes = env.rpc(headers, "ping")["result"];
234  BEAST_EXPECT(rpcRes["role"] == "proxied");
235  BEAST_EXPECT(
236  rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:9.10.11.12");
237  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
238 
239  headers["X-Forwarded-For"] =
240  "[2001:db8:3333:4444:5555:6666:13.14.15.16], [a:b:c:d:e:f], "
241  "[g:h:i:j:k:l]";
242  rpcRes = env.rpc(headers, "ping")["result"];
243  BEAST_EXPECT(rpcRes["role"] == "proxied");
244  BEAST_EXPECT(
245  rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:13.14.15.16");
246  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
247 
248  headers = {};
249  headers["Forwarded"] =
250  "for=\"[2001:db8:3333:4444:5555:6666:20.19.18.17]\"";
251  rpcRes = env.rpc(headers, "ping")["result"];
252  BEAST_EXPECT(rpcRes["role"] == "proxied");
253  BEAST_EXPECT(
254  rpcRes["ip"] == "2001:db8:3333:4444:5555:6666:20.19.18.17");
255  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
256 
257  headers["Forwarded"] =
258  "For=\"[2001:db8:bb:cc::24.23.22.21]\", for=99.00.11.22";
259  rpcRes = env.rpc(headers, "ping")["result"];
260  BEAST_EXPECT(rpcRes["role"] == "proxied");
261  BEAST_EXPECT(rpcRes["ip"] == "2001:db8:bb:cc::24.23.22.21");
262  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
263 
264  headers["Forwarded"] =
265  "proto=http;FOR=\"[::11:22:33:44:45.55.65.75]:234\""
266  ";by=203.0.113.43";
267  rpcRes = env.rpc(headers, "ping")["result"];
268  BEAST_EXPECT(rpcRes["role"] == "proxied");
269  BEAST_EXPECT(rpcRes["ip"] == "::11:22:33:44:45.55.65.75");
270  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
271  }
272 
273  {
274  Env env{*this, envconfig(admin_localnet)};
275  BEAST_EXPECT(env.rpc("ping")["result"]["role"] == "admin");
276  BEAST_EXPECT(makeWSClient(env.app().config())
277  ->invoke("ping")["result"]["unlimited"]
278  .asBool());
279  }
280 
281  {
283  BEAST_EXPECT(env.rpc("ping")["result"]["role"] == "proxied");
284  auto wsRes =
285  makeWSClient(env.app().config())->invoke("ping")["result"];
286  BEAST_EXPECT(
287  !wsRes.isMember("unlimited") || !wsRes["unlimited"].asBool());
288 
290  headers["X-Forwarded-For"] = "12.34.56.78";
291  Json::Value rpcRes = env.rpc(headers, "ping")["result"];
292  BEAST_EXPECT(rpcRes["role"] == "proxied");
293  BEAST_EXPECT(rpcRes["ip"] == "12.34.56.78");
294  BEAST_EXPECT(isValidIpAddress(rpcRes["ip"].asString()));
295  }
296  }
297 
298  void
300  {
301  using namespace test::jtx;
302 
303  {
304  Env env(*this);
305 
307  Json::Value rpcRes;
308 
309  // No "for=" in Forwarded.
310  headers["Forwarded"] = "for 88.77.66.55";
311  rpcRes = env.rpc(headers, "ping")["result"];
312  BEAST_EXPECT(rpcRes["role"] == "admin");
313  BEAST_EXPECT(!rpcRes.isMember("ip"));
314 
315  headers["Forwarded"] = "by=88.77.66.55";
316  rpcRes = env.rpc(headers, "ping")["result"];
317  BEAST_EXPECT(rpcRes["role"] == "admin");
318  BEAST_EXPECT(!rpcRes.isMember("ip"));
319 
320  // Empty field.
321  headers = {};
322  headers["Forwarded"] = "for=";
323  rpcRes = env.rpc(headers, "ping")["result"];
324  BEAST_EXPECT(rpcRes["role"] == "admin");
325  BEAST_EXPECT(!rpcRes.isMember("ip"));
326 
327  headers = {};
328  headers["X-Forwarded-For"] = " ";
329  rpcRes = env.rpc(headers, "ping")["result"];
330  BEAST_EXPECT(rpcRes["role"] == "admin");
331  BEAST_EXPECT(!rpcRes.isMember("ip"));
332 
333  // Empty quotes.
334  headers = {};
335  headers["Forwarded"] = "for= \" \" ";
336  rpcRes = env.rpc(headers, "ping")["result"];
337  BEAST_EXPECT(rpcRes["role"] == "admin");
338  BEAST_EXPECT(!rpcRes.isMember("ip"));
339 
340  headers = {};
341  headers["X-Forwarded-For"] = "\"\"";
342  rpcRes = env.rpc(headers, "ping")["result"];
343  BEAST_EXPECT(rpcRes["role"] == "admin");
344  BEAST_EXPECT(!rpcRes.isMember("ip"));
345 
346  // Unbalanced outer quotes.
347  headers = {};
348  headers["X-Forwarded-For"] = "\"12.34.56.78 ";
349  rpcRes = env.rpc(headers, "ping")["result"];
350  BEAST_EXPECT(rpcRes["role"] == "admin");
351  BEAST_EXPECT(!rpcRes.isMember("ip"));
352 
353  headers["X-Forwarded-For"] = "12.34.56.78\"";
354  rpcRes = env.rpc(headers, "ping")["result"];
355  BEAST_EXPECT(rpcRes["role"] == "admin");
356  BEAST_EXPECT(!rpcRes.isMember("ip"));
357 
358  // Unbalanced square brackets for IPv6.
359  headers = {};
360  headers["Forwarded"] = "FOR=[2001:db8:bb:cc::";
361  rpcRes = env.rpc(headers, "ping")["result"];
362  BEAST_EXPECT(rpcRes["role"] == "admin");
363  BEAST_EXPECT(!rpcRes.isMember("ip"));
364 
365  headers = {};
366  headers["X-Forwarded-For"] = "2001:db8:bb:cc::24.23.22.21]";
367  rpcRes = env.rpc(headers, "ping")["result"];
368  BEAST_EXPECT(rpcRes["role"] == "admin");
369  BEAST_EXPECT(!rpcRes.isMember("ip"));
370 
371  // Empty square brackets.
372  headers = {};
373  headers["Forwarded"] = "FOR=[]";
374  rpcRes = env.rpc(headers, "ping")["result"];
375  BEAST_EXPECT(rpcRes["role"] == "admin");
376  BEAST_EXPECT(!rpcRes.isMember("ip"));
377 
378  headers = {};
379  headers["X-Forwarded-For"] = "\" [ ] \"";
380  rpcRes = env.rpc(headers, "ping")["result"];
381  BEAST_EXPECT(rpcRes["role"] == "admin");
382  BEAST_EXPECT(!rpcRes.isMember("ip"));
383  }
384  }
385 
386 public:
387  void
388  run() override
389  {
390  testRoles();
392  }
393 };
394 
395 BEAST_DEFINE_TESTSUITE(Roles, app, ripple);
396 
397 } // namespace test
398 
399 } // namespace ripple
ripple::test::jtx::secure_gateway
std::unique_ptr< Config > secure_gateway(std::unique_ptr< Config >)
Definition: envconfig.cpp:87
std::string
STL class.
ripple::test::Roles_test::isValidIpAddress
bool isValidIpAddress(std::string const &addr)
Definition: Roles_test.cpp:38
ripple::test::Roles_test::run
void run() override
Definition: Roles_test.cpp:388
ripple::test::jtx::Env::app
Application & app()
Definition: Env.h:241
ripple::test::jtx::envconfig
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:49
ripple::test::jtx::admin_localnet
std::unique_ptr< Config > admin_localnet(std::unique_ptr< Config >)
Definition: envconfig.cpp:96
ripple::test::jtx::no_admin
std::unique_ptr< Config > no_admin(std::unique_ptr< Config >)
adjust config so no admin ports are enabled
Definition: envconfig.cpp:79
ripple::test::Roles_test
Definition: Roles_test.cpp:35
ripple::Application::config
virtual Config & config()=0
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
ripple::test::Roles_test::testRoles
void testRoles()
Definition: Roles_test.cpp:46
ripple::test::Roles_test::testInvalidIpAddresses
void testInvalidIpAddresses()
Definition: Roles_test.cpp:299
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::test::makeWSClient
std::unique_ptr< WSClient > makeWSClient(Config const &cfg, bool v2, unsigned rpc_version, std::unordered_map< std::string, std::string > const &headers)
Returns a client operating through WebSockets/S.
Definition: WSClient.cpp:300
ripple::test::jtx::secure_gateway_localnet
std::unique_ptr< Config > secure_gateway_localnet(std::unique_ptr< Config >)
Definition: envconfig.cpp:104
unordered_map
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
ripple::test::jtx::Env::rpc
Json::Value rpc(std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition: Env.h:687
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::test::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(DeliverMin, app, ripple)
string