]>
Commit | Line | Data |
---|---|---|
31f18b77 FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | /* | |
4 | * Ceph - scalable distributed file system | |
5 | * | |
6 | * Copyright (C) 2015 Red Hat | |
7 | * | |
8 | * This is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public | |
10 | * License version 2.1, as published by the Free Software | |
11 | * Foundation. See file COPYING. | |
12 | * | |
13 | */ | |
14 | ||
15 | #include <string> | |
16 | ||
17 | #include <boost/intrusive_ptr.hpp> | |
18 | #include <boost/optional.hpp> | |
19 | ||
20 | #include <gtest/gtest.h> | |
21 | ||
b32b8144 | 22 | #include "include/stringify.h" |
31f18b77 FG |
23 | #include "common/code_environment.h" |
24 | #include "common/ceph_context.h" | |
25 | #include "global/global_init.h" | |
26 | #include "rgw/rgw_auth.h" | |
27 | #include "rgw/rgw_iam_policy.h" | |
b32b8144 | 28 | #include "rgw/rgw_op.h" |
31f18b77 FG |
29 | |
30 | ||
31 | using std::string; | |
32 | using std::vector; | |
33 | ||
34 | using boost::container::flat_set; | |
35 | using boost::intrusive_ptr; | |
36 | using boost::make_optional; | |
37 | using boost::none; | |
38 | using boost::optional; | |
39 | ||
40 | using rgw::auth::Identity; | |
41 | using rgw::auth::Principal; | |
42 | ||
43 | using rgw::IAM::ARN; | |
44 | using rgw::IAM::Effect; | |
45 | using rgw::IAM::Environment; | |
46 | using rgw::IAM::Partition; | |
47 | using rgw::IAM::Policy; | |
48 | using rgw::IAM::s3All; | |
49 | using rgw::IAM::s3Count; | |
50 | using rgw::IAM::s3GetAccelerateConfiguration; | |
51 | using rgw::IAM::s3GetBucketAcl; | |
52 | using rgw::IAM::s3GetBucketCORS; | |
53 | using rgw::IAM::s3GetBucketLocation; | |
54 | using rgw::IAM::s3GetBucketLogging; | |
55 | using rgw::IAM::s3GetBucketNotification; | |
56 | using rgw::IAM::s3GetBucketPolicy; | |
57 | using rgw::IAM::s3GetBucketRequestPayment; | |
58 | using rgw::IAM::s3GetBucketTagging; | |
59 | using rgw::IAM::s3GetBucketVersioning; | |
60 | using rgw::IAM::s3GetBucketWebsite; | |
61 | using rgw::IAM::s3GetLifecycleConfiguration; | |
62 | using rgw::IAM::s3GetObject; | |
63 | using rgw::IAM::s3GetObjectAcl; | |
64 | using rgw::IAM::s3GetObjectVersionAcl; | |
65 | using rgw::IAM::s3GetObjectTorrent; | |
d2e6a577 | 66 | using rgw::IAM::s3GetObjectTagging; |
31f18b77 | 67 | using rgw::IAM::s3GetObjectVersion; |
d2e6a577 | 68 | using rgw::IAM::s3GetObjectVersionTagging; |
31f18b77 FG |
69 | using rgw::IAM::s3GetObjectVersionTorrent; |
70 | using rgw::IAM::s3GetReplicationConfiguration; | |
71 | using rgw::IAM::s3ListAllMyBuckets; | |
72 | using rgw::IAM::s3ListBucket; | |
73 | using rgw::IAM::s3ListBucket; | |
28e407b8 | 74 | using rgw::IAM::s3ListBucketMultipartUploads; |
31f18b77 FG |
75 | using rgw::IAM::s3ListBucketVersions; |
76 | using rgw::IAM::s3ListMultipartUploadParts; | |
77 | using rgw::IAM::s3None; | |
78 | using rgw::IAM::s3PutBucketAcl; | |
79 | using rgw::IAM::s3PutBucketPolicy; | |
80 | using rgw::IAM::Service; | |
81 | using rgw::IAM::TokenID; | |
82 | using rgw::IAM::Version; | |
83 | ||
84 | class FakeIdentity : public Identity { | |
85 | const Principal id; | |
86 | public: | |
87 | ||
88 | FakeIdentity(Principal&& id) : id(std::move(id)) {} | |
89 | uint32_t get_perms_from_aclspec(const aclspec_t& aclspec) const override { | |
90 | abort(); | |
91 | return 0; | |
92 | }; | |
93 | ||
94 | bool is_admin_of(const rgw_user& uid) const override { | |
95 | abort(); | |
96 | return false; | |
97 | } | |
98 | ||
99 | bool is_owner_of(const rgw_user& uid) const override { | |
100 | abort(); | |
101 | return false; | |
102 | } | |
103 | ||
104 | virtual uint32_t get_perm_mask() const override { | |
105 | abort(); | |
106 | return 0; | |
107 | } | |
108 | ||
109 | void to_str(std::ostream& out) const override { | |
b32b8144 | 110 | out << id; |
31f18b77 FG |
111 | } |
112 | ||
113 | bool is_identity(const flat_set<Principal>& ids) const override { | |
b32b8144 FG |
114 | if (id.is_wildcard() && (!ids.empty())) { |
115 | return true; | |
116 | } | |
117 | return ids.find(id) != ids.end() || ids.find(Principal::wildcard()) != ids.end(); | |
31f18b77 FG |
118 | } |
119 | }; | |
120 | ||
121 | class PolicyTest : public ::testing::Test { | |
122 | protected: | |
123 | intrusive_ptr<CephContext> cct; | |
124 | static const string arbitrary_tenant; | |
125 | static string example1; | |
126 | static string example2; | |
127 | static string example3; | |
128 | public: | |
129 | PolicyTest() { | |
130 | cct = new CephContext(CEPH_ENTITY_TYPE_CLIENT); | |
131 | } | |
132 | }; | |
133 | ||
134 | TEST_F(PolicyTest, Parse1) { | |
135 | optional<Policy> p; | |
136 | ||
137 | ASSERT_NO_THROW(p = Policy(cct.get(), arbitrary_tenant, | |
138 | bufferlist::static_from_string(example1))); | |
139 | ASSERT_TRUE(p); | |
140 | ||
141 | EXPECT_EQ(p->text, example1); | |
142 | EXPECT_EQ(p->version, Version::v2012_10_17); | |
143 | EXPECT_FALSE(p->id); | |
144 | EXPECT_FALSE(p->statements[0].sid); | |
145 | EXPECT_FALSE(p->statements.empty()); | |
146 | EXPECT_EQ(p->statements.size(), 1U); | |
147 | EXPECT_TRUE(p->statements[0].princ.empty()); | |
148 | EXPECT_TRUE(p->statements[0].noprinc.empty()); | |
149 | EXPECT_EQ(p->statements[0].effect, Effect::Allow); | |
150 | EXPECT_EQ(p->statements[0].action, s3ListBucket); | |
151 | EXPECT_EQ(p->statements[0].notaction, s3None); | |
152 | ASSERT_FALSE(p->statements[0].resource.empty()); | |
153 | ASSERT_EQ(p->statements[0].resource.size(), 1U); | |
154 | EXPECT_EQ(p->statements[0].resource.begin()->partition, Partition::aws); | |
155 | EXPECT_EQ(p->statements[0].resource.begin()->service, Service::s3); | |
156 | EXPECT_TRUE(p->statements[0].resource.begin()->region.empty()); | |
157 | EXPECT_EQ(p->statements[0].resource.begin()->account, arbitrary_tenant); | |
158 | EXPECT_EQ(p->statements[0].resource.begin()->resource, "example_bucket"); | |
159 | EXPECT_TRUE(p->statements[0].notresource.empty()); | |
160 | EXPECT_TRUE(p->statements[0].conditions.empty()); | |
161 | } | |
162 | ||
163 | TEST_F(PolicyTest, Eval1) { | |
164 | auto p = Policy(cct.get(), arbitrary_tenant, | |
165 | bufferlist::static_from_string(example1)); | |
166 | Environment e; | |
167 | ||
168 | EXPECT_EQ(p.eval(e, none, s3ListBucket, | |
169 | ARN(Partition::aws, Service::s3, | |
170 | "", arbitrary_tenant, "example_bucket")), | |
171 | Effect::Allow); | |
172 | ||
173 | EXPECT_EQ(p.eval(e, none, s3PutBucketAcl, | |
174 | ARN(Partition::aws, Service::s3, | |
175 | "", arbitrary_tenant, "example_bucket")), | |
176 | Effect::Pass); | |
177 | ||
178 | EXPECT_EQ(p.eval(e, none, s3ListBucket, | |
179 | ARN(Partition::aws, Service::s3, | |
180 | "", arbitrary_tenant, "erroneous_bucket")), | |
181 | Effect::Pass); | |
182 | ||
183 | } | |
184 | ||
185 | TEST_F(PolicyTest, Parse2) { | |
186 | optional<Policy> p; | |
187 | ||
188 | ASSERT_NO_THROW(p = Policy(cct.get(), arbitrary_tenant, | |
189 | bufferlist::static_from_string(example2))); | |
190 | ASSERT_TRUE(p); | |
191 | ||
192 | EXPECT_EQ(p->text, example2); | |
193 | EXPECT_EQ(p->version, Version::v2012_10_17); | |
194 | EXPECT_EQ(*p->id, "S3-Account-Permissions"); | |
195 | ASSERT_FALSE(p->statements.empty()); | |
196 | EXPECT_EQ(p->statements.size(), 1U); | |
197 | EXPECT_EQ(*p->statements[0].sid, "1"); | |
198 | EXPECT_FALSE(p->statements[0].princ.empty()); | |
199 | EXPECT_EQ(p->statements[0].princ.size(), 1U); | |
200 | EXPECT_EQ(*p->statements[0].princ.begin(), | |
201 | Principal::tenant("ACCOUNT-ID-WITHOUT-HYPHENS")); | |
202 | EXPECT_TRUE(p->statements[0].noprinc.empty()); | |
203 | EXPECT_EQ(p->statements[0].effect, Effect::Allow); | |
204 | EXPECT_EQ(p->statements[0].action, s3All); | |
205 | EXPECT_EQ(p->statements[0].notaction, s3None); | |
206 | ASSERT_FALSE(p->statements[0].resource.empty()); | |
207 | ASSERT_EQ(p->statements[0].resource.size(), 2U); | |
208 | EXPECT_EQ(p->statements[0].resource.begin()->partition, Partition::aws); | |
209 | EXPECT_EQ(p->statements[0].resource.begin()->service, Service::s3); | |
210 | EXPECT_TRUE(p->statements[0].resource.begin()->region.empty()); | |
211 | EXPECT_EQ(p->statements[0].resource.begin()->account, arbitrary_tenant); | |
212 | EXPECT_EQ(p->statements[0].resource.begin()->resource, "mybucket"); | |
213 | EXPECT_EQ((p->statements[0].resource.begin() + 1)->partition, | |
214 | Partition::aws); | |
215 | EXPECT_EQ((p->statements[0].resource.begin() + 1)->service, | |
216 | Service::s3); | |
217 | EXPECT_TRUE((p->statements[0].resource.begin() + 1)->region.empty()); | |
218 | EXPECT_EQ((p->statements[0].resource.begin() + 1)->account, | |
219 | arbitrary_tenant); | |
220 | EXPECT_EQ((p->statements[0].resource.begin() + 1)->resource, "mybucket/*"); | |
221 | EXPECT_TRUE(p->statements[0].notresource.empty()); | |
222 | EXPECT_TRUE(p->statements[0].conditions.empty()); | |
223 | } | |
224 | ||
225 | TEST_F(PolicyTest, Eval2) { | |
226 | auto p = Policy(cct.get(), arbitrary_tenant, | |
227 | bufferlist::static_from_string(example2)); | |
228 | Environment e; | |
229 | ||
230 | auto trueacct = FakeIdentity( | |
231 | Principal::tenant("ACCOUNT-ID-WITHOUT-HYPHENS")); | |
232 | ||
233 | auto notacct = FakeIdentity( | |
234 | Principal::tenant("some-other-account")); | |
235 | for (auto i = 0ULL; i < s3Count; ++i) { | |
236 | EXPECT_EQ(p.eval(e, trueacct, 1ULL << i, | |
237 | ARN(Partition::aws, Service::s3, | |
238 | "", arbitrary_tenant, "mybucket")), | |
239 | Effect::Allow); | |
240 | EXPECT_EQ(p.eval(e, trueacct, 1ULL << i, | |
241 | ARN(Partition::aws, Service::s3, | |
242 | "", arbitrary_tenant, "mybucket/myobject")), | |
243 | Effect::Allow); | |
244 | ||
245 | EXPECT_EQ(p.eval(e, notacct, 1ULL << i, | |
246 | ARN(Partition::aws, Service::s3, | |
247 | "", arbitrary_tenant, "mybucket")), | |
248 | Effect::Pass); | |
249 | EXPECT_EQ(p.eval(e, notacct, 1ULL << i, | |
250 | ARN(Partition::aws, Service::s3, | |
251 | "", arbitrary_tenant, "mybucket/myobject")), | |
252 | Effect::Pass); | |
253 | ||
254 | EXPECT_EQ(p.eval(e, trueacct, 1ULL << i, | |
255 | ARN(Partition::aws, Service::s3, | |
256 | "", arbitrary_tenant, "notyourbucket")), | |
257 | Effect::Pass); | |
258 | EXPECT_EQ(p.eval(e, trueacct, 1ULL << i, | |
259 | ARN(Partition::aws, Service::s3, | |
260 | "", arbitrary_tenant, "notyourbucket/notyourobject")), | |
261 | Effect::Pass); | |
262 | ||
263 | } | |
264 | } | |
265 | ||
266 | TEST_F(PolicyTest, Parse3) { | |
267 | optional<Policy> p; | |
268 | ||
269 | ASSERT_NO_THROW(p = Policy(cct.get(), arbitrary_tenant, | |
270 | bufferlist::static_from_string(example3))); | |
271 | ASSERT_TRUE(p); | |
272 | ||
273 | EXPECT_EQ(p->text, example3); | |
274 | EXPECT_EQ(p->version, Version::v2012_10_17); | |
275 | EXPECT_FALSE(p->id); | |
276 | ASSERT_FALSE(p->statements.empty()); | |
277 | EXPECT_EQ(p->statements.size(), 3U); | |
278 | ||
279 | EXPECT_EQ(*p->statements[0].sid, "FirstStatement"); | |
280 | EXPECT_TRUE(p->statements[0].princ.empty()); | |
281 | EXPECT_TRUE(p->statements[0].noprinc.empty()); | |
282 | EXPECT_EQ(p->statements[0].effect, Effect::Allow); | |
283 | EXPECT_EQ(p->statements[0].action, s3PutBucketPolicy); | |
284 | EXPECT_EQ(p->statements[0].notaction, s3None); | |
285 | ASSERT_FALSE(p->statements[0].resource.empty()); | |
286 | ASSERT_EQ(p->statements[0].resource.size(), 1U); | |
287 | EXPECT_EQ(p->statements[0].resource.begin()->partition, Partition::wildcard); | |
288 | EXPECT_EQ(p->statements[0].resource.begin()->service, Service::wildcard); | |
289 | EXPECT_EQ(p->statements[0].resource.begin()->region, "*"); | |
290 | EXPECT_EQ(p->statements[0].resource.begin()->account, arbitrary_tenant); | |
291 | EXPECT_EQ(p->statements[0].resource.begin()->resource, "*"); | |
292 | EXPECT_TRUE(p->statements[0].notresource.empty()); | |
293 | EXPECT_TRUE(p->statements[0].conditions.empty()); | |
294 | ||
295 | EXPECT_EQ(*p->statements[1].sid, "SecondStatement"); | |
296 | EXPECT_TRUE(p->statements[1].princ.empty()); | |
297 | EXPECT_TRUE(p->statements[1].noprinc.empty()); | |
298 | EXPECT_EQ(p->statements[1].effect, Effect::Allow); | |
299 | EXPECT_EQ(p->statements[1].action, s3ListAllMyBuckets); | |
300 | EXPECT_EQ(p->statements[1].notaction, s3None); | |
301 | ASSERT_FALSE(p->statements[1].resource.empty()); | |
302 | ASSERT_EQ(p->statements[1].resource.size(), 1U); | |
303 | EXPECT_EQ(p->statements[1].resource.begin()->partition, Partition::wildcard); | |
304 | EXPECT_EQ(p->statements[1].resource.begin()->service, Service::wildcard); | |
305 | EXPECT_EQ(p->statements[1].resource.begin()->region, "*"); | |
306 | EXPECT_EQ(p->statements[1].resource.begin()->account, arbitrary_tenant); | |
307 | EXPECT_EQ(p->statements[1].resource.begin()->resource, "*"); | |
308 | EXPECT_TRUE(p->statements[1].notresource.empty()); | |
309 | EXPECT_TRUE(p->statements[1].conditions.empty()); | |
310 | ||
311 | EXPECT_EQ(*p->statements[2].sid, "ThirdStatement"); | |
312 | EXPECT_TRUE(p->statements[2].princ.empty()); | |
313 | EXPECT_TRUE(p->statements[2].noprinc.empty()); | |
314 | EXPECT_EQ(p->statements[2].effect, Effect::Allow); | |
315 | EXPECT_EQ(p->statements[2].action, (s3ListMultipartUploadParts | | |
316 | s3ListBucket | s3ListBucketVersions | | |
317 | s3ListAllMyBuckets | | |
28e407b8 | 318 | s3ListBucketMultipartUploads | |
31f18b77 FG |
319 | s3GetObject | s3GetObjectVersion | |
320 | s3GetObjectAcl | s3GetObjectVersionAcl | | |
321 | s3GetObjectTorrent | | |
322 | s3GetObjectVersionTorrent | | |
323 | s3GetAccelerateConfiguration | | |
324 | s3GetBucketAcl | s3GetBucketCORS | | |
325 | s3GetBucketVersioning | | |
326 | s3GetBucketRequestPayment | | |
327 | s3GetBucketLocation | | |
328 | s3GetBucketPolicy | | |
329 | s3GetBucketNotification | | |
330 | s3GetBucketLogging | | |
331 | s3GetBucketTagging | | |
332 | s3GetBucketWebsite | | |
333 | s3GetLifecycleConfiguration | | |
d2e6a577 FG |
334 | s3GetReplicationConfiguration | |
335 | s3GetObjectTagging | | |
336 | s3GetObjectVersionTagging)); | |
31f18b77 FG |
337 | EXPECT_EQ(p->statements[2].notaction, s3None); |
338 | ASSERT_FALSE(p->statements[2].resource.empty()); | |
339 | ASSERT_EQ(p->statements[2].resource.size(), 2U); | |
340 | EXPECT_EQ(p->statements[2].resource.begin()->partition, Partition::aws); | |
341 | EXPECT_EQ(p->statements[2].resource.begin()->service, Service::s3); | |
342 | EXPECT_TRUE(p->statements[2].resource.begin()->region.empty()); | |
343 | EXPECT_EQ(p->statements[2].resource.begin()->account, arbitrary_tenant); | |
344 | EXPECT_EQ(p->statements[2].resource.begin()->resource, "confidential-data"); | |
345 | EXPECT_EQ((p->statements[2].resource.begin() + 1)->partition, | |
346 | Partition::aws); | |
347 | EXPECT_EQ((p->statements[2].resource.begin() + 1)->service, Service::s3); | |
348 | EXPECT_TRUE((p->statements[2].resource.begin() + 1)->region.empty()); | |
349 | EXPECT_EQ((p->statements[2].resource.begin() + 1)->account, | |
350 | arbitrary_tenant); | |
351 | EXPECT_EQ((p->statements[2].resource.begin() + 1)->resource, | |
352 | "confidential-data/*"); | |
353 | EXPECT_TRUE(p->statements[2].notresource.empty()); | |
354 | ASSERT_FALSE(p->statements[2].conditions.empty()); | |
355 | ASSERT_EQ(p->statements[2].conditions.size(), 1U); | |
356 | EXPECT_EQ(p->statements[2].conditions[0].op, TokenID::Bool); | |
357 | EXPECT_EQ(p->statements[2].conditions[0].key, "aws:MultiFactorAuthPresent"); | |
358 | EXPECT_FALSE(p->statements[2].conditions[0].ifexists); | |
359 | ASSERT_FALSE(p->statements[2].conditions[0].vals.empty()); | |
360 | EXPECT_EQ(p->statements[2].conditions[0].vals.size(), 1U); | |
361 | EXPECT_EQ(p->statements[2].conditions[0].vals[0], "true"); | |
362 | } | |
363 | ||
364 | TEST_F(PolicyTest, Eval3) { | |
365 | auto p = Policy(cct.get(), arbitrary_tenant, | |
366 | bufferlist::static_from_string(example3)); | |
367 | Environment em; | |
368 | Environment tr = { { "aws:MultiFactorAuthPresent", "true" } }; | |
369 | Environment fa = { { "aws:MultiFactorAuthPresent", "false" } }; | |
370 | ||
371 | auto s3allow = (s3ListMultipartUploadParts | s3ListBucket | | |
372 | s3ListBucketVersions | s3ListAllMyBuckets | | |
28e407b8 | 373 | s3ListBucketMultipartUploads | s3GetObject | |
31f18b77 FG |
374 | s3GetObjectVersion | s3GetObjectAcl | s3GetObjectVersionAcl | |
375 | s3GetObjectTorrent | s3GetObjectVersionTorrent | | |
376 | s3GetAccelerateConfiguration | s3GetBucketAcl | | |
377 | s3GetBucketCORS | s3GetBucketVersioning | | |
378 | s3GetBucketRequestPayment | s3GetBucketLocation | | |
379 | s3GetBucketPolicy | s3GetBucketNotification | | |
380 | s3GetBucketLogging | s3GetBucketTagging | | |
381 | s3GetBucketWebsite | s3GetLifecycleConfiguration | | |
d2e6a577 FG |
382 | s3GetReplicationConfiguration | |
383 | s3GetObjectTagging | s3GetObjectVersionTagging); | |
31f18b77 FG |
384 | |
385 | EXPECT_EQ(p.eval(em, none, s3PutBucketPolicy, | |
386 | ARN(Partition::aws, Service::s3, | |
387 | "", arbitrary_tenant, "mybucket")), | |
388 | Effect::Allow); | |
389 | ||
390 | EXPECT_EQ(p.eval(em, none, s3PutBucketPolicy, | |
391 | ARN(Partition::aws, Service::s3, | |
392 | "", arbitrary_tenant, "mybucket")), | |
393 | Effect::Allow); | |
394 | ||
395 | ||
396 | for (auto i = 0ULL; i < s3Count; ++i) { | |
397 | auto op = 1ULL << i; | |
398 | if ((op == s3ListAllMyBuckets) || (op == s3PutBucketPolicy)) { | |
399 | continue; | |
400 | } | |
401 | ||
402 | EXPECT_EQ(p.eval(em, none, op, | |
403 | ARN(Partition::aws, Service::s3, | |
404 | "", arbitrary_tenant, "confidential-data")), | |
405 | Effect::Pass); | |
406 | EXPECT_EQ(p.eval(tr, none, op, | |
407 | ARN(Partition::aws, Service::s3, | |
408 | "", arbitrary_tenant, "confidential-data")), | |
409 | op & s3allow ? Effect::Allow : Effect::Pass); | |
410 | EXPECT_EQ(p.eval(fa, none, op, | |
411 | ARN(Partition::aws, Service::s3, | |
412 | "", arbitrary_tenant, "confidential-data")), | |
413 | Effect::Pass); | |
414 | ||
415 | EXPECT_EQ(p.eval(em, none, op, | |
416 | ARN(Partition::aws, Service::s3, | |
417 | "", arbitrary_tenant, "confidential-data/moo")), | |
418 | Effect::Pass); | |
419 | EXPECT_EQ(p.eval(tr, none, op, | |
420 | ARN(Partition::aws, Service::s3, | |
421 | "", arbitrary_tenant, "confidential-data/moo")), | |
422 | op & s3allow ? Effect::Allow : Effect::Pass); | |
423 | EXPECT_EQ(p.eval(fa, none, op, | |
424 | ARN(Partition::aws, Service::s3, | |
425 | "", arbitrary_tenant, "confidential-data/moo")), | |
426 | Effect::Pass); | |
427 | ||
428 | EXPECT_EQ(p.eval(em, none, op, | |
429 | ARN(Partition::aws, Service::s3, | |
430 | "", arbitrary_tenant, "really-confidential-data")), | |
431 | Effect::Pass); | |
432 | EXPECT_EQ(p.eval(tr, none, op, | |
433 | ARN(Partition::aws, Service::s3, | |
434 | "", arbitrary_tenant, "really-confidential-data")), | |
435 | Effect::Pass); | |
436 | EXPECT_EQ(p.eval(fa, none, op, | |
437 | ARN(Partition::aws, Service::s3, | |
438 | "", arbitrary_tenant, "really-confidential-data")), | |
439 | Effect::Pass); | |
440 | ||
441 | EXPECT_EQ(p.eval(em, none, op, | |
442 | ARN(Partition::aws, Service::s3, | |
443 | "", arbitrary_tenant, | |
444 | "really-confidential-data/moo")), Effect::Pass); | |
445 | EXPECT_EQ(p.eval(tr, none, op, | |
446 | ARN(Partition::aws, Service::s3, | |
447 | "", arbitrary_tenant, | |
448 | "really-confidential-data/moo")), Effect::Pass); | |
449 | EXPECT_EQ(p.eval(fa, none, op, | |
450 | ARN(Partition::aws, Service::s3, | |
451 | "", arbitrary_tenant, | |
452 | "really-confidential-data/moo")), Effect::Pass); | |
453 | ||
454 | } | |
455 | } | |
456 | ||
457 | const string PolicyTest::arbitrary_tenant = "arbitrary_tenant"; | |
458 | string PolicyTest::example1 = R"( | |
459 | { | |
460 | "Version": "2012-10-17", | |
461 | "Statement": { | |
462 | "Effect": "Allow", | |
463 | "Action": "s3:ListBucket", | |
464 | "Resource": "arn:aws:s3:::example_bucket" | |
465 | } | |
466 | } | |
467 | )"; | |
468 | ||
469 | string PolicyTest::example2 = R"( | |
470 | { | |
471 | "Version": "2012-10-17", | |
472 | "Id": "S3-Account-Permissions", | |
473 | "Statement": [{ | |
474 | "Sid": "1", | |
475 | "Effect": "Allow", | |
476 | "Principal": {"AWS": ["arn:aws:iam::ACCOUNT-ID-WITHOUT-HYPHENS:root"]}, | |
477 | "Action": "s3:*", | |
478 | "Resource": [ | |
479 | "arn:aws:s3:::mybucket", | |
480 | "arn:aws:s3:::mybucket/*" | |
481 | ] | |
482 | }] | |
483 | } | |
484 | )"; | |
485 | ||
486 | string PolicyTest::example3 = R"( | |
487 | { | |
488 | "Version": "2012-10-17", | |
489 | "Statement": [ | |
490 | { | |
491 | "Sid": "FirstStatement", | |
492 | "Effect": "Allow", | |
493 | "Action": ["s3:PutBucketPolicy"], | |
494 | "Resource": "*" | |
495 | }, | |
496 | { | |
497 | "Sid": "SecondStatement", | |
498 | "Effect": "Allow", | |
499 | "Action": "s3:ListAllMyBuckets", | |
500 | "Resource": "*" | |
501 | }, | |
502 | { | |
503 | "Sid": "ThirdStatement", | |
504 | "Effect": "Allow", | |
505 | "Action": [ | |
506 | "s3:List*", | |
507 | "s3:Get*" | |
508 | ], | |
509 | "Resource": [ | |
510 | "arn:aws:s3:::confidential-data", | |
511 | "arn:aws:s3:::confidential-data/*" | |
512 | ], | |
513 | "Condition": {"Bool": {"aws:MultiFactorAuthPresent": "true"}} | |
514 | } | |
515 | ] | |
516 | } | |
517 | )"; | |
d2e6a577 | 518 | |
b32b8144 FG |
519 | class IPPolicyTest : public ::testing::Test { |
520 | protected: | |
521 | intrusive_ptr<CephContext> cct; | |
522 | static const string arbitrary_tenant; | |
523 | static string ip_address_allow_example; | |
524 | static string ip_address_deny_example; | |
525 | static string ip_address_full_example; | |
526 | // 192.168.1.0/24 | |
527 | const rgw::IAM::MaskedIP allowedIPv4Range = { false, rgw::IAM::Address("11000000101010000000000100000000"), 24 }; | |
528 | // 192.168.1.1/32 | |
529 | const rgw::IAM::MaskedIP blacklistedIPv4 = { false, rgw::IAM::Address("11000000101010000000000100000001"), 32 }; | |
530 | // 2001:db8:85a3:0:0:8a2e:370:7334/128 | |
531 | const rgw::IAM::MaskedIP allowedIPv6 = { true, rgw::IAM::Address("00100000000000010000110110111000100001011010001100000000000000000000000000000000100010100010111000000011011100000111001100110100"), 128 }; | |
532 | // ::1 | |
533 | const rgw::IAM::MaskedIP blacklistedIPv6 = { true, rgw::IAM::Address(1), 128 }; | |
534 | // 2001:db8:85a3:0:0:8a2e:370:7330/124 | |
535 | const rgw::IAM::MaskedIP allowedIPv6Range = { true, rgw::IAM::Address("00100000000000010000110110111000100001011010001100000000000000000000000000000000100010100010111000000011011100000111001100110000"), 124 }; | |
536 | public: | |
537 | IPPolicyTest() { | |
538 | cct = new CephContext(CEPH_ENTITY_TYPE_CLIENT); | |
539 | } | |
540 | }; | |
541 | const string IPPolicyTest::arbitrary_tenant = "arbitrary_tenant"; | |
542 | ||
543 | TEST_F(IPPolicyTest, MaskedIPOperations) { | |
544 | EXPECT_EQ(stringify(allowedIPv4Range), "192.168.1.0/24"); | |
545 | EXPECT_EQ(stringify(blacklistedIPv4), "192.168.1.1/32"); | |
546 | EXPECT_EQ(stringify(allowedIPv6), "2001:db8:85a3:0:0:8a2e:370:7334/128"); | |
547 | EXPECT_EQ(stringify(allowedIPv6Range), "2001:db8:85a3:0:0:8a2e:370:7330/124"); | |
548 | EXPECT_EQ(stringify(blacklistedIPv6), "0:0:0:0:0:0:0:1/128"); | |
549 | EXPECT_EQ(allowedIPv4Range, blacklistedIPv4); | |
550 | EXPECT_EQ(allowedIPv6Range, allowedIPv6); | |
551 | } | |
552 | ||
553 | TEST_F(IPPolicyTest, asNetworkIPv4Range) { | |
554 | auto actualIPv4Range = rgw::IAM::Condition::as_network("192.168.1.0/24"); | |
555 | ASSERT_TRUE(actualIPv4Range.is_initialized()); | |
556 | EXPECT_EQ(*actualIPv4Range, allowedIPv4Range); | |
557 | } | |
558 | ||
559 | TEST_F(IPPolicyTest, asNetworkIPv4) { | |
560 | auto actualIPv4 = rgw::IAM::Condition::as_network("192.168.1.1"); | |
561 | ASSERT_TRUE(actualIPv4.is_initialized()); | |
562 | EXPECT_EQ(*actualIPv4, blacklistedIPv4); | |
563 | } | |
564 | ||
565 | TEST_F(IPPolicyTest, asNetworkIPv6Range) { | |
566 | auto actualIPv6Range = rgw::IAM::Condition::as_network("2001:db8:85a3:0:0:8a2e:370:7330/124"); | |
567 | ASSERT_TRUE(actualIPv6Range.is_initialized()); | |
568 | EXPECT_EQ(*actualIPv6Range, allowedIPv6Range); | |
569 | } | |
570 | ||
571 | TEST_F(IPPolicyTest, asNetworkIPv6) { | |
572 | auto actualIPv6 = rgw::IAM::Condition::as_network("2001:db8:85a3:0:0:8a2e:370:7334"); | |
573 | ASSERT_TRUE(actualIPv6.is_initialized()); | |
574 | EXPECT_EQ(*actualIPv6, allowedIPv6); | |
575 | } | |
576 | ||
577 | TEST_F(IPPolicyTest, asNetworkInvalid) { | |
578 | EXPECT_FALSE(rgw::IAM::Condition::as_network("")); | |
579 | EXPECT_FALSE(rgw::IAM::Condition::as_network("192.168.1.1/33")); | |
580 | EXPECT_FALSE(rgw::IAM::Condition::as_network("2001:db8:85a3:0:0:8a2e:370:7334/129")); | |
581 | EXPECT_FALSE(rgw::IAM::Condition::as_network("192.168.1.1:")); | |
582 | EXPECT_FALSE(rgw::IAM::Condition::as_network("1.2.3.10000")); | |
583 | } | |
584 | ||
585 | TEST_F(IPPolicyTest, IPEnvironment) { | |
586 | // Unfortunately RGWCivetWeb is too tightly tied to civetweb to test RGWCivetWeb::init_env. | |
587 | RGWEnv rgw_env; | |
588 | RGWUserInfo user; | |
589 | RGWRados rgw_rados; | |
590 | rgw_env.set("REMOTE_ADDR", "192.168.1.1"); | |
591 | rgw_env.set("HTTP_HOST", "1.2.3.4"); | |
592 | req_state rgw_req_state(cct.get(), &rgw_env, &user); | |
593 | Environment iam_env = rgw_build_iam_environment(&rgw_rados, &rgw_req_state); | |
594 | auto ip = iam_env.find("aws:SourceIp"); | |
595 | ASSERT_NE(ip, iam_env.end()); | |
596 | EXPECT_EQ(ip->second, "192.168.1.1"); | |
597 | ||
598 | ASSERT_EQ(cct.get()->_conf->set_val("rgw_remote_addr_param", "SOME_VAR"), 0); | |
599 | EXPECT_EQ(cct.get()->_conf->rgw_remote_addr_param, "SOME_VAR"); | |
600 | iam_env = rgw_build_iam_environment(&rgw_rados, &rgw_req_state); | |
601 | ip = iam_env.find("aws:SourceIp"); | |
602 | EXPECT_EQ(ip, iam_env.end()); | |
603 | ||
604 | rgw_env.set("SOME_VAR", "192.168.1.2"); | |
605 | iam_env = rgw_build_iam_environment(&rgw_rados, &rgw_req_state); | |
606 | ip = iam_env.find("aws:SourceIp"); | |
607 | ASSERT_NE(ip, iam_env.end()); | |
608 | EXPECT_EQ(ip->second, "192.168.1.2"); | |
609 | ||
610 | ASSERT_EQ(cct.get()->_conf->set_val("rgw_remote_addr_param", "HTTP_X_FORWARDED_FOR"), 0); | |
611 | rgw_env.set("HTTP_X_FORWARDED_FOR", "192.168.1.3"); | |
612 | iam_env = rgw_build_iam_environment(&rgw_rados, &rgw_req_state); | |
613 | ip = iam_env.find("aws:SourceIp"); | |
614 | ASSERT_NE(ip, iam_env.end()); | |
615 | EXPECT_EQ(ip->second, "192.168.1.3"); | |
616 | ||
617 | rgw_env.set("HTTP_X_FORWARDED_FOR", "192.168.1.4, 4.3.2.1, 2001:db8:85a3:8d3:1319:8a2e:370:7348"); | |
618 | iam_env = rgw_build_iam_environment(&rgw_rados, &rgw_req_state); | |
619 | ip = iam_env.find("aws:SourceIp"); | |
620 | ASSERT_NE(ip, iam_env.end()); | |
621 | EXPECT_EQ(ip->second, "192.168.1.4"); | |
622 | } | |
623 | ||
624 | TEST_F(IPPolicyTest, ParseIPAddress) { | |
625 | optional<Policy> p; | |
626 | ||
627 | ASSERT_NO_THROW(p = Policy(cct.get(), arbitrary_tenant, | |
628 | bufferlist::static_from_string(ip_address_full_example))); | |
629 | ASSERT_TRUE(p); | |
630 | ||
631 | EXPECT_EQ(p->text, ip_address_full_example); | |
632 | EXPECT_EQ(p->version, Version::v2012_10_17); | |
633 | EXPECT_EQ(*p->id, "S3IPPolicyTest"); | |
634 | EXPECT_FALSE(p->statements.empty()); | |
635 | EXPECT_EQ(p->statements.size(), 1U); | |
636 | EXPECT_EQ(*p->statements[0].sid, "IPAllow"); | |
637 | EXPECT_FALSE(p->statements[0].princ.empty()); | |
638 | EXPECT_EQ(p->statements[0].princ.size(), 1U); | |
639 | EXPECT_EQ(*p->statements[0].princ.begin(), | |
640 | Principal::wildcard()); | |
641 | EXPECT_TRUE(p->statements[0].noprinc.empty()); | |
642 | EXPECT_EQ(p->statements[0].effect, Effect::Allow); | |
643 | EXPECT_EQ(p->statements[0].action, s3ListBucket); | |
644 | EXPECT_EQ(p->statements[0].notaction, s3None); | |
645 | ASSERT_FALSE(p->statements[0].resource.empty()); | |
646 | ASSERT_EQ(p->statements[0].resource.size(), 2U); | |
647 | EXPECT_EQ(p->statements[0].resource.begin()->partition, Partition::aws); | |
648 | EXPECT_EQ(p->statements[0].resource.begin()->service, Service::s3); | |
649 | EXPECT_TRUE(p->statements[0].resource.begin()->region.empty()); | |
650 | EXPECT_EQ(p->statements[0].resource.begin()->account, arbitrary_tenant); | |
651 | EXPECT_EQ(p->statements[0].resource.begin()->resource, "example_bucket"); | |
652 | EXPECT_EQ((p->statements[0].resource.begin() + 1)->resource, "example_bucket/*"); | |
653 | EXPECT_TRUE(p->statements[0].notresource.empty()); | |
654 | ASSERT_FALSE(p->statements[0].conditions.empty()); | |
655 | ASSERT_EQ(p->statements[0].conditions.size(), 2U); | |
656 | EXPECT_EQ(p->statements[0].conditions[0].op, TokenID::IpAddress); | |
657 | EXPECT_EQ(p->statements[0].conditions[0].key, "aws:SourceIp"); | |
658 | ASSERT_FALSE(p->statements[0].conditions[0].vals.empty()); | |
659 | EXPECT_EQ(p->statements[0].conditions[0].vals.size(), 2U); | |
660 | EXPECT_EQ(p->statements[0].conditions[0].vals[0], "192.168.1.0/24"); | |
661 | EXPECT_EQ(p->statements[0].conditions[0].vals[1], "::1"); | |
662 | optional<rgw::IAM::MaskedIP> convertedIPv4 = rgw::IAM::Condition::as_network(p->statements[0].conditions[0].vals[0]); | |
663 | EXPECT_TRUE(convertedIPv4.is_initialized()); | |
664 | if (convertedIPv4.is_initialized()) { | |
665 | EXPECT_EQ(*convertedIPv4, allowedIPv4Range); | |
666 | } | |
667 | ||
668 | EXPECT_EQ(p->statements[0].conditions[1].op, TokenID::NotIpAddress); | |
669 | EXPECT_EQ(p->statements[0].conditions[1].key, "aws:SourceIp"); | |
670 | ASSERT_FALSE(p->statements[0].conditions[1].vals.empty()); | |
671 | EXPECT_EQ(p->statements[0].conditions[1].vals.size(), 2U); | |
672 | EXPECT_EQ(p->statements[0].conditions[1].vals[0], "192.168.1.1/32"); | |
673 | EXPECT_EQ(p->statements[0].conditions[1].vals[1], "2001:0db8:85a3:0000:0000:8a2e:0370:7334"); | |
674 | optional<rgw::IAM::MaskedIP> convertedIPv6 = rgw::IAM::Condition::as_network(p->statements[0].conditions[1].vals[1]); | |
675 | EXPECT_TRUE(convertedIPv6.is_initialized()); | |
676 | if (convertedIPv6.is_initialized()) { | |
677 | EXPECT_EQ(*convertedIPv6, allowedIPv6); | |
678 | } | |
679 | } | |
680 | ||
681 | TEST_F(IPPolicyTest, EvalIPAddress) { | |
682 | auto allowp = Policy(cct.get(), arbitrary_tenant, | |
683 | bufferlist::static_from_string(ip_address_allow_example)); | |
684 | auto denyp = Policy(cct.get(), arbitrary_tenant, | |
685 | bufferlist::static_from_string(ip_address_deny_example)); | |
686 | auto fullp = Policy(cct.get(), arbitrary_tenant, | |
687 | bufferlist::static_from_string(ip_address_full_example)); | |
688 | Environment e; | |
689 | Environment allowedIP, blacklistedIP, allowedIPv6, blacklistedIPv6; | |
690 | allowedIP["aws:SourceIp"] = "192.168.1.2"; | |
691 | allowedIPv6["aws:SourceIp"] = "::1"; | |
692 | blacklistedIP["aws:SourceIp"] = "192.168.1.1"; | |
693 | blacklistedIPv6["aws:SourceIp"] = "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; | |
694 | ||
695 | auto trueacct = FakeIdentity( | |
696 | Principal::tenant("ACCOUNT-ID-WITHOUT-HYPHENS")); | |
697 | // Without an IP address in the environment then evaluation will always pass | |
698 | EXPECT_EQ(allowp.eval(e, trueacct, s3ListBucket, | |
699 | ARN(Partition::aws, Service::s3, | |
700 | "", arbitrary_tenant, "example_bucket")), | |
701 | Effect::Pass); | |
702 | EXPECT_EQ(fullp.eval(e, trueacct, s3ListBucket, | |
703 | ARN(Partition::aws, Service::s3, | |
704 | "", arbitrary_tenant, "example_bucket/myobject")), | |
705 | Effect::Pass); | |
706 | ||
707 | EXPECT_EQ(allowp.eval(allowedIP, trueacct, s3ListBucket, | |
708 | ARN(Partition::aws, Service::s3, | |
709 | "", arbitrary_tenant, "example_bucket")), | |
710 | Effect::Allow); | |
711 | EXPECT_EQ(allowp.eval(blacklistedIPv6, trueacct, s3ListBucket, | |
712 | ARN(Partition::aws, Service::s3, | |
713 | "", arbitrary_tenant, "example_bucket")), | |
714 | Effect::Pass); | |
715 | ||
716 | ||
717 | EXPECT_EQ(denyp.eval(allowedIP, trueacct, s3ListBucket, | |
718 | ARN(Partition::aws, Service::s3, | |
719 | "", arbitrary_tenant, "example_bucket")), | |
720 | Effect::Deny); | |
721 | EXPECT_EQ(denyp.eval(allowedIP, trueacct, s3ListBucket, | |
722 | ARN(Partition::aws, Service::s3, | |
723 | "", arbitrary_tenant, "example_bucket/myobject")), | |
724 | Effect::Deny); | |
725 | ||
726 | EXPECT_EQ(denyp.eval(blacklistedIP, trueacct, s3ListBucket, | |
727 | ARN(Partition::aws, Service::s3, | |
728 | "", arbitrary_tenant, "example_bucket")), | |
729 | Effect::Pass); | |
730 | EXPECT_EQ(denyp.eval(blacklistedIP, trueacct, s3ListBucket, | |
731 | ARN(Partition::aws, Service::s3, | |
732 | "", arbitrary_tenant, "example_bucket/myobject")), | |
733 | Effect::Pass); | |
734 | ||
735 | EXPECT_EQ(denyp.eval(blacklistedIPv6, trueacct, s3ListBucket, | |
736 | ARN(Partition::aws, Service::s3, | |
737 | "", arbitrary_tenant, "example_bucket")), | |
738 | Effect::Pass); | |
739 | EXPECT_EQ(denyp.eval(blacklistedIPv6, trueacct, s3ListBucket, | |
740 | ARN(Partition::aws, Service::s3, | |
741 | "", arbitrary_tenant, "example_bucket/myobject")), | |
742 | Effect::Pass); | |
743 | EXPECT_EQ(denyp.eval(allowedIPv6, trueacct, s3ListBucket, | |
744 | ARN(Partition::aws, Service::s3, | |
745 | "", arbitrary_tenant, "example_bucket")), | |
746 | Effect::Deny); | |
747 | EXPECT_EQ(denyp.eval(allowedIPv6, trueacct, s3ListBucket, | |
748 | ARN(Partition::aws, Service::s3, | |
749 | "", arbitrary_tenant, "example_bucket/myobject")), | |
750 | Effect::Deny); | |
751 | ||
752 | EXPECT_EQ(fullp.eval(allowedIP, trueacct, s3ListBucket, | |
753 | ARN(Partition::aws, Service::s3, | |
754 | "", arbitrary_tenant, "example_bucket")), | |
755 | Effect::Allow); | |
756 | EXPECT_EQ(fullp.eval(allowedIP, trueacct, s3ListBucket, | |
757 | ARN(Partition::aws, Service::s3, | |
758 | "", arbitrary_tenant, "example_bucket/myobject")), | |
759 | Effect::Allow); | |
760 | ||
761 | EXPECT_EQ(fullp.eval(blacklistedIP, trueacct, s3ListBucket, | |
762 | ARN(Partition::aws, Service::s3, | |
763 | "", arbitrary_tenant, "example_bucket")), | |
764 | Effect::Pass); | |
765 | EXPECT_EQ(fullp.eval(blacklistedIP, trueacct, s3ListBucket, | |
766 | ARN(Partition::aws, Service::s3, | |
767 | "", arbitrary_tenant, "example_bucket/myobject")), | |
768 | Effect::Pass); | |
769 | ||
770 | EXPECT_EQ(fullp.eval(allowedIPv6, trueacct, s3ListBucket, | |
771 | ARN(Partition::aws, Service::s3, | |
772 | "", arbitrary_tenant, "example_bucket")), | |
773 | Effect::Allow); | |
774 | EXPECT_EQ(fullp.eval(allowedIPv6, trueacct, s3ListBucket, | |
775 | ARN(Partition::aws, Service::s3, | |
776 | "", arbitrary_tenant, "example_bucket/myobject")), | |
777 | Effect::Allow); | |
778 | ||
779 | EXPECT_EQ(fullp.eval(blacklistedIPv6, trueacct, s3ListBucket, | |
780 | ARN(Partition::aws, Service::s3, | |
781 | "", arbitrary_tenant, "example_bucket")), | |
782 | Effect::Pass); | |
783 | EXPECT_EQ(fullp.eval(blacklistedIPv6, trueacct, s3ListBucket, | |
784 | ARN(Partition::aws, Service::s3, | |
785 | "", arbitrary_tenant, "example_bucket/myobject")), | |
786 | Effect::Pass); | |
787 | } | |
788 | ||
789 | string IPPolicyTest::ip_address_allow_example = R"( | |
790 | { | |
791 | "Version": "2012-10-17", | |
792 | "Id": "S3SimpleIPPolicyTest", | |
793 | "Statement": [{ | |
794 | "Sid": "1", | |
795 | "Effect": "Allow", | |
796 | "Principal": {"AWS": ["arn:aws:iam::ACCOUNT-ID-WITHOUT-HYPHENS:root"]}, | |
797 | "Action": "s3:ListBucket", | |
798 | "Resource": [ | |
799 | "arn:aws:s3:::example_bucket" | |
800 | ], | |
801 | "Condition": { | |
802 | "IpAddress": {"aws:SourceIp": "192.168.1.0/24"} | |
803 | } | |
804 | }] | |
805 | } | |
806 | )"; | |
807 | ||
808 | string IPPolicyTest::ip_address_deny_example = R"( | |
809 | { | |
810 | "Version": "2012-10-17", | |
811 | "Id": "S3IPPolicyTest", | |
812 | "Statement": { | |
813 | "Effect": "Deny", | |
814 | "Sid": "IPDeny", | |
815 | "Action": "s3:ListBucket", | |
816 | "Principal": {"AWS": ["arn:aws:iam::ACCOUNT-ID-WITHOUT-HYPHENS:root"]}, | |
817 | "Resource": [ | |
818 | "arn:aws:s3:::example_bucket", | |
819 | "arn:aws:s3:::example_bucket/*" | |
820 | ], | |
821 | "Condition": { | |
822 | "NotIpAddress": {"aws:SourceIp": ["192.168.1.1/32", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"]} | |
823 | } | |
824 | } | |
825 | } | |
826 | )"; | |
827 | ||
828 | string IPPolicyTest::ip_address_full_example = R"( | |
829 | { | |
830 | "Version": "2012-10-17", | |
831 | "Id": "S3IPPolicyTest", | |
832 | "Statement": { | |
833 | "Effect": "Allow", | |
834 | "Sid": "IPAllow", | |
835 | "Action": "s3:ListBucket", | |
836 | "Principal": "*", | |
837 | "Resource": [ | |
838 | "arn:aws:s3:::example_bucket", | |
839 | "arn:aws:s3:::example_bucket/*" | |
840 | ], | |
841 | "Condition": { | |
842 | "IpAddress": {"aws:SourceIp": ["192.168.1.0/24", "::1"]}, | |
843 | "NotIpAddress": {"aws:SourceIp": ["192.168.1.1/32", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"]} | |
844 | } | |
845 | } | |
846 | } | |
847 | )"; | |
848 | ||
d2e6a577 FG |
849 | TEST(MatchWildcards, Simple) |
850 | { | |
851 | EXPECT_TRUE(match_wildcards("", "")); | |
852 | EXPECT_TRUE(match_wildcards("", "", MATCH_CASE_INSENSITIVE)); | |
853 | EXPECT_FALSE(match_wildcards("", "abc")); | |
854 | EXPECT_FALSE(match_wildcards("", "abc", MATCH_CASE_INSENSITIVE)); | |
855 | EXPECT_FALSE(match_wildcards("abc", "")); | |
856 | EXPECT_FALSE(match_wildcards("abc", "", MATCH_CASE_INSENSITIVE)); | |
857 | EXPECT_TRUE(match_wildcards("abc", "abc")); | |
858 | EXPECT_TRUE(match_wildcards("abc", "abc", MATCH_CASE_INSENSITIVE)); | |
859 | EXPECT_FALSE(match_wildcards("abc", "abC")); | |
860 | EXPECT_TRUE(match_wildcards("abc", "abC", MATCH_CASE_INSENSITIVE)); | |
861 | EXPECT_FALSE(match_wildcards("abC", "abc")); | |
862 | EXPECT_TRUE(match_wildcards("abC", "abc", MATCH_CASE_INSENSITIVE)); | |
863 | EXPECT_FALSE(match_wildcards("abc", "abcd")); | |
864 | EXPECT_FALSE(match_wildcards("abc", "abcd", MATCH_CASE_INSENSITIVE)); | |
865 | EXPECT_FALSE(match_wildcards("abcd", "abc")); | |
866 | EXPECT_FALSE(match_wildcards("abcd", "abc", MATCH_CASE_INSENSITIVE)); | |
867 | } | |
868 | ||
869 | TEST(MatchWildcards, QuestionMark) | |
870 | { | |
871 | EXPECT_FALSE(match_wildcards("?", "")); | |
872 | EXPECT_FALSE(match_wildcards("?", "", MATCH_CASE_INSENSITIVE)); | |
873 | EXPECT_TRUE(match_wildcards("?", "a")); | |
874 | EXPECT_TRUE(match_wildcards("?", "a", MATCH_CASE_INSENSITIVE)); | |
875 | EXPECT_TRUE(match_wildcards("?bc", "abc")); | |
876 | EXPECT_TRUE(match_wildcards("?bc", "abc", MATCH_CASE_INSENSITIVE)); | |
877 | EXPECT_TRUE(match_wildcards("a?c", "abc")); | |
878 | EXPECT_TRUE(match_wildcards("a?c", "abc", MATCH_CASE_INSENSITIVE)); | |
879 | EXPECT_FALSE(match_wildcards("abc", "a?c")); | |
880 | EXPECT_FALSE(match_wildcards("abc", "a?c", MATCH_CASE_INSENSITIVE)); | |
881 | EXPECT_FALSE(match_wildcards("a?c", "abC")); | |
882 | EXPECT_TRUE(match_wildcards("a?c", "abC", MATCH_CASE_INSENSITIVE)); | |
883 | EXPECT_TRUE(match_wildcards("ab?", "abc")); | |
884 | EXPECT_TRUE(match_wildcards("ab?", "abc", MATCH_CASE_INSENSITIVE)); | |
885 | EXPECT_TRUE(match_wildcards("a?c?e", "abcde")); | |
886 | EXPECT_TRUE(match_wildcards("a?c?e", "abcde", MATCH_CASE_INSENSITIVE)); | |
887 | EXPECT_TRUE(match_wildcards("???", "abc")); | |
888 | EXPECT_TRUE(match_wildcards("???", "abc", MATCH_CASE_INSENSITIVE)); | |
889 | EXPECT_FALSE(match_wildcards("???", "abcd")); | |
890 | EXPECT_FALSE(match_wildcards("???", "abcd", MATCH_CASE_INSENSITIVE)); | |
891 | } | |
892 | ||
893 | TEST(MatchWildcards, Asterisk) | |
894 | { | |
895 | EXPECT_TRUE(match_wildcards("*", "")); | |
896 | EXPECT_TRUE(match_wildcards("*", "", MATCH_CASE_INSENSITIVE)); | |
897 | EXPECT_FALSE(match_wildcards("", "*")); | |
898 | EXPECT_FALSE(match_wildcards("", "*", MATCH_CASE_INSENSITIVE)); | |
899 | EXPECT_FALSE(match_wildcards("*a", "")); | |
900 | EXPECT_FALSE(match_wildcards("*a", "", MATCH_CASE_INSENSITIVE)); | |
901 | EXPECT_TRUE(match_wildcards("*a", "a")); | |
902 | EXPECT_TRUE(match_wildcards("*a", "a", MATCH_CASE_INSENSITIVE)); | |
903 | EXPECT_TRUE(match_wildcards("a*", "a")); | |
904 | EXPECT_TRUE(match_wildcards("a*", "a", MATCH_CASE_INSENSITIVE)); | |
905 | EXPECT_TRUE(match_wildcards("a*c", "ac")); | |
906 | EXPECT_TRUE(match_wildcards("a*c", "ac", MATCH_CASE_INSENSITIVE)); | |
907 | EXPECT_TRUE(match_wildcards("a*c", "abbc")); | |
908 | EXPECT_TRUE(match_wildcards("a*c", "abbc", MATCH_CASE_INSENSITIVE)); | |
909 | EXPECT_FALSE(match_wildcards("a*c", "abbC")); | |
910 | EXPECT_TRUE(match_wildcards("a*c", "abbC", MATCH_CASE_INSENSITIVE)); | |
911 | EXPECT_TRUE(match_wildcards("a*c*e", "abBce")); | |
912 | EXPECT_TRUE(match_wildcards("a*c*e", "abBce", MATCH_CASE_INSENSITIVE)); | |
913 | EXPECT_TRUE(match_wildcards("http://*.example.com", | |
914 | "http://www.example.com")); | |
915 | EXPECT_TRUE(match_wildcards("http://*.example.com", | |
916 | "http://www.example.com", MATCH_CASE_INSENSITIVE)); | |
917 | EXPECT_FALSE(match_wildcards("http://*.example.com", | |
918 | "http://www.Example.com")); | |
919 | EXPECT_TRUE(match_wildcards("http://*.example.com", | |
920 | "http://www.Example.com", MATCH_CASE_INSENSITIVE)); | |
921 | EXPECT_TRUE(match_wildcards("http://example.com/*", | |
922 | "http://example.com/index.html")); | |
923 | EXPECT_TRUE(match_wildcards("http://example.com/*/*.jpg", | |
924 | "http://example.com/fun/smiley.jpg")); | |
925 | // note: parsing of * is not greedy, so * does not match 'bc' here | |
926 | EXPECT_FALSE(match_wildcards("a*c", "abcc")); | |
927 | EXPECT_FALSE(match_wildcards("a*c", "abcc", MATCH_CASE_INSENSITIVE)); | |
928 | } | |
929 | ||
930 | TEST(MatchPolicy, Action) | |
931 | { | |
932 | constexpr auto flag = MATCH_POLICY_ACTION; | |
933 | EXPECT_TRUE(match_policy("a:b:c", "a:b:c", flag)); | |
934 | EXPECT_TRUE(match_policy("a:b:c", "A:B:C", flag)); // case insensitive | |
935 | EXPECT_TRUE(match_policy("a:*:e", "a:bcd:e", flag)); | |
936 | EXPECT_FALSE(match_policy("a:*", "a:b:c", flag)); // cannot span segments | |
937 | } | |
938 | ||
939 | TEST(MatchPolicy, Resource) | |
940 | { | |
941 | constexpr auto flag = MATCH_POLICY_RESOURCE; | |
942 | EXPECT_TRUE(match_policy("a:b:c", "a:b:c", flag)); | |
943 | EXPECT_FALSE(match_policy("a:b:c", "A:B:C", flag)); // case sensitive | |
944 | EXPECT_TRUE(match_policy("a:*:e", "a:bcd:e", flag)); | |
945 | EXPECT_FALSE(match_policy("a:*", "a:b:c", flag)); // cannot span segments | |
946 | } | |
947 | ||
948 | TEST(MatchPolicy, ARN) | |
949 | { | |
950 | constexpr auto flag = MATCH_POLICY_ARN; | |
951 | EXPECT_TRUE(match_policy("a:b:c", "a:b:c", flag)); | |
952 | EXPECT_TRUE(match_policy("a:b:c", "A:B:C", flag)); // case insensitive | |
953 | EXPECT_TRUE(match_policy("a:*:e", "a:bcd:e", flag)); | |
954 | EXPECT_FALSE(match_policy("a:*", "a:b:c", flag)); // cannot span segments | |
955 | } | |
956 | ||
957 | TEST(MatchPolicy, String) | |
958 | { | |
959 | constexpr auto flag = MATCH_POLICY_STRING; | |
960 | EXPECT_TRUE(match_policy("a:b:c", "a:b:c", flag)); | |
961 | EXPECT_FALSE(match_policy("a:b:c", "A:B:C", flag)); // case sensitive | |
962 | EXPECT_TRUE(match_policy("a:*:e", "a:bcd:e", flag)); | |
963 | EXPECT_FALSE(match_policy("a:*", "a:b:c", flag)); // cannot span segments | |
964 | } |