1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2015 Red Hat
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.
17 #include <boost/intrusive_ptr.hpp>
18 #include <boost/optional.hpp>
20 #include <gtest/gtest.h>
22 #include "include/stringify.h"
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"
28 #include "rgw/rgw_op.h"
34 using boost::container::flat_set
;
35 using boost::intrusive_ptr
;
36 using boost::make_optional
;
38 using boost::optional
;
40 using rgw::auth::Identity
;
41 using rgw::auth::Principal
;
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
;
66 using rgw::IAM::s3GetObjectTagging
;
67 using rgw::IAM::s3GetObjectVersion
;
68 using rgw::IAM::s3GetObjectVersionTagging
;
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
;
74 using rgw::IAM::s3ListBucketMultipartUploads
;
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
;
84 class FakeIdentity
: public Identity
{
88 FakeIdentity(Principal
&& id
) : id(std::move(id
)) {}
89 uint32_t get_perms_from_aclspec(const aclspec_t
& aclspec
) const override
{
94 bool is_admin_of(const rgw_user
& uid
) const override
{
99 bool is_owner_of(const rgw_user
& uid
) const override
{
104 virtual uint32_t get_perm_mask() const override
{
109 void to_str(std::ostream
& out
) const override
{
113 bool is_identity(const flat_set
<Principal
>& ids
) const override
{
114 if (id
.is_wildcard() && (!ids
.empty())) {
117 return ids
.find(id
) != ids
.end() || ids
.find(Principal::wildcard()) != ids
.end();
121 class PolicyTest
: public ::testing::Test
{
123 intrusive_ptr
<CephContext
> cct
;
124 static const string arbitrary_tenant
;
125 static string example1
;
126 static string example2
;
127 static string example3
;
130 cct
= new CephContext(CEPH_ENTITY_TYPE_CLIENT
);
134 TEST_F(PolicyTest
, Parse1
) {
137 ASSERT_NO_THROW(p
= Policy(cct
.get(), arbitrary_tenant
,
138 bufferlist::static_from_string(example1
)));
141 EXPECT_EQ(p
->text
, example1
);
142 EXPECT_EQ(p
->version
, Version::v2012_10_17
);
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());
163 TEST_F(PolicyTest
, Eval1
) {
164 auto p
= Policy(cct
.get(), arbitrary_tenant
,
165 bufferlist::static_from_string(example1
));
168 EXPECT_EQ(p
.eval(e
, none
, s3ListBucket
,
169 ARN(Partition::aws
, Service::s3
,
170 "", arbitrary_tenant
, "example_bucket")),
173 EXPECT_EQ(p
.eval(e
, none
, s3PutBucketAcl
,
174 ARN(Partition::aws
, Service::s3
,
175 "", arbitrary_tenant
, "example_bucket")),
178 EXPECT_EQ(p
.eval(e
, none
, s3ListBucket
,
179 ARN(Partition::aws
, Service::s3
,
180 "", arbitrary_tenant
, "erroneous_bucket")),
185 TEST_F(PolicyTest
, Parse2
) {
188 ASSERT_NO_THROW(p
= Policy(cct
.get(), arbitrary_tenant
,
189 bufferlist::static_from_string(example2
)));
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
,
215 EXPECT_EQ((p
->statements
[0].resource
.begin() + 1)->service
,
217 EXPECT_TRUE((p
->statements
[0].resource
.begin() + 1)->region
.empty());
218 EXPECT_EQ((p
->statements
[0].resource
.begin() + 1)->account
,
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());
225 TEST_F(PolicyTest
, Eval2
) {
226 auto p
= Policy(cct
.get(), arbitrary_tenant
,
227 bufferlist::static_from_string(example2
));
230 auto trueacct
= FakeIdentity(
231 Principal::tenant("ACCOUNT-ID-WITHOUT-HYPHENS"));
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")),
240 EXPECT_EQ(p
.eval(e
, trueacct
, 1ULL << i
,
241 ARN(Partition::aws
, Service::s3
,
242 "", arbitrary_tenant
, "mybucket/myobject")),
245 EXPECT_EQ(p
.eval(e
, notacct
, 1ULL << i
,
246 ARN(Partition::aws
, Service::s3
,
247 "", arbitrary_tenant
, "mybucket")),
249 EXPECT_EQ(p
.eval(e
, notacct
, 1ULL << i
,
250 ARN(Partition::aws
, Service::s3
,
251 "", arbitrary_tenant
, "mybucket/myobject")),
254 EXPECT_EQ(p
.eval(e
, trueacct
, 1ULL << i
,
255 ARN(Partition::aws
, Service::s3
,
256 "", arbitrary_tenant
, "notyourbucket")),
258 EXPECT_EQ(p
.eval(e
, trueacct
, 1ULL << i
,
259 ARN(Partition::aws
, Service::s3
,
260 "", arbitrary_tenant
, "notyourbucket/notyourobject")),
266 TEST_F(PolicyTest
, Parse3
) {
269 ASSERT_NO_THROW(p
= Policy(cct
.get(), arbitrary_tenant
,
270 bufferlist::static_from_string(example3
)));
273 EXPECT_EQ(p
->text
, example3
);
274 EXPECT_EQ(p
->version
, Version::v2012_10_17
);
276 ASSERT_FALSE(p
->statements
.empty());
277 EXPECT_EQ(p
->statements
.size(), 3U);
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());
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());
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
|
318 s3ListBucketMultipartUploads
|
319 s3GetObject
| s3GetObjectVersion
|
320 s3GetObjectAcl
| s3GetObjectVersionAcl
|
322 s3GetObjectVersionTorrent
|
323 s3GetAccelerateConfiguration
|
324 s3GetBucketAcl
| s3GetBucketCORS
|
325 s3GetBucketVersioning
|
326 s3GetBucketRequestPayment
|
327 s3GetBucketLocation
|
329 s3GetBucketNotification
|
333 s3GetLifecycleConfiguration
|
334 s3GetReplicationConfiguration
|
336 s3GetObjectVersionTagging
));
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
,
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
,
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");
364 TEST_F(PolicyTest
, Eval3
) {
365 auto p
= Policy(cct
.get(), arbitrary_tenant
,
366 bufferlist::static_from_string(example3
));
368 Environment tr
= { { "aws:MultiFactorAuthPresent", "true" } };
369 Environment fa
= { { "aws:MultiFactorAuthPresent", "false" } };
371 auto s3allow
= (s3ListMultipartUploadParts
| s3ListBucket
|
372 s3ListBucketVersions
| s3ListAllMyBuckets
|
373 s3ListBucketMultipartUploads
| s3GetObject
|
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
|
382 s3GetReplicationConfiguration
|
383 s3GetObjectTagging
| s3GetObjectVersionTagging
);
385 EXPECT_EQ(p
.eval(em
, none
, s3PutBucketPolicy
,
386 ARN(Partition::aws
, Service::s3
,
387 "", arbitrary_tenant
, "mybucket")),
390 EXPECT_EQ(p
.eval(em
, none
, s3PutBucketPolicy
,
391 ARN(Partition::aws
, Service::s3
,
392 "", arbitrary_tenant
, "mybucket")),
396 for (auto i
= 0ULL; i
< s3Count
; ++i
) {
398 if ((op
== s3ListAllMyBuckets
) || (op
== s3PutBucketPolicy
)) {
402 EXPECT_EQ(p
.eval(em
, none
, op
,
403 ARN(Partition::aws
, Service::s3
,
404 "", arbitrary_tenant
, "confidential-data")),
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")),
415 EXPECT_EQ(p
.eval(em
, none
, op
,
416 ARN(Partition::aws
, Service::s3
,
417 "", arbitrary_tenant
, "confidential-data/moo")),
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")),
428 EXPECT_EQ(p
.eval(em
, none
, op
,
429 ARN(Partition::aws
, Service::s3
,
430 "", arbitrary_tenant
, "really-confidential-data")),
432 EXPECT_EQ(p
.eval(tr
, none
, op
,
433 ARN(Partition::aws
, Service::s3
,
434 "", arbitrary_tenant
, "really-confidential-data")),
436 EXPECT_EQ(p
.eval(fa
, none
, op
,
437 ARN(Partition::aws
, Service::s3
,
438 "", arbitrary_tenant
, "really-confidential-data")),
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
);
457 const string
PolicyTest::arbitrary_tenant
= "arbitrary_tenant";
458 string
PolicyTest::example1
= R
"(
460 "Version
": "2012-10-17",
463 "Action
": "s3
:ListBucket
",
464 "Resource
": "arn
:aws
:s3:::example_bucket
"
469 string
PolicyTest::example2
= R
"(
471 "Version
": "2012-10-17",
472 "Id
": "S3
-Account
-Permissions
",
476 "Principal
": {"AWS
": ["arn
:aws
:iam::ACCOUNT
-ID
-WITHOUT
-HYPHENS
:root
"]},
479 "arn
:aws
:s3:::mybucket
",
480 "arn
:aws
:s3:::mybucket
/*"
486 string PolicyTest::example3 = R"(
488 "Version": "2012-10-17",
491 "Sid": "FirstStatement",
493 "Action": ["s3:PutBucketPolicy"],
497 "Sid": "SecondStatement",
499 "Action": "s3:ListAllMyBuckets",
503 "Sid": "ThirdStatement",
510 "arn:aws:s3:::confidential-data",
511 "arn:aws:s3:::confidential-data/*"
513 "Condition": {"Bool": {"aws:MultiFactorAuthPresent": "true"}}
519 class IPPolicyTest : public ::testing::Test {
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;
527 const rgw::IAM::MaskedIP allowedIPv4Range = { false, rgw::IAM::Address("11000000101010000000000100000000"), 24 };
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 };
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 };
538 cct = new CephContext(CEPH_ENTITY_TYPE_CLIENT);
541 const string IPPolicyTest::arbitrary_tenant = "arbitrary_tenant";
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);
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);
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);
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);
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);
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"));
585 TEST_F(IPPolicyTest, IPEnvironment) {
586 // Unfortunately RGWCivetWeb is too tightly tied to civetweb to test RGWCivetWeb::init_env.
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");
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());
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");
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");
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");
624 TEST_F(IPPolicyTest, ParseIPAddress) {
627 ASSERT_NO_THROW(p = Policy(cct.get(), arbitrary_tenant,
628 bufferlist::static_from_string(ip_address_full_example)));
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);
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);
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));
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";
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")),
702 EXPECT_EQ(fullp.eval(e, trueacct, s3ListBucket,
703 ARN(Partition::aws, Service::s3,
704 "", arbitrary_tenant, "example_bucket/myobject")),
707 EXPECT_EQ(allowp.eval(allowedIP, trueacct, s3ListBucket,
708 ARN(Partition::aws, Service::s3,
709 "", arbitrary_tenant, "example_bucket")),
711 EXPECT_EQ(allowp.eval(blacklistedIPv6, trueacct, s3ListBucket,
712 ARN(Partition::aws, Service::s3,
713 "", arbitrary_tenant, "example_bucket")),
717 EXPECT_EQ(denyp.eval(allowedIP, trueacct, s3ListBucket,
718 ARN(Partition::aws, Service::s3,
719 "", arbitrary_tenant, "example_bucket")),
721 EXPECT_EQ(denyp.eval(allowedIP, trueacct, s3ListBucket,
722 ARN(Partition::aws, Service::s3,
723 "", arbitrary_tenant, "example_bucket/myobject")),
726 EXPECT_EQ(denyp.eval(blacklistedIP, trueacct, s3ListBucket,
727 ARN(Partition::aws, Service::s3,
728 "", arbitrary_tenant, "example_bucket")),
730 EXPECT_EQ(denyp.eval(blacklistedIP, trueacct, s3ListBucket,
731 ARN(Partition::aws, Service::s3,
732 "", arbitrary_tenant, "example_bucket/myobject")),
735 EXPECT_EQ(denyp.eval(blacklistedIPv6, trueacct, s3ListBucket,
736 ARN(Partition::aws, Service::s3,
737 "", arbitrary_tenant, "example_bucket")),
739 EXPECT_EQ(denyp.eval(blacklistedIPv6, trueacct, s3ListBucket,
740 ARN(Partition::aws, Service::s3,
741 "", arbitrary_tenant, "example_bucket/myobject")),
743 EXPECT_EQ(denyp.eval(allowedIPv6, trueacct, s3ListBucket,
744 ARN(Partition::aws, Service::s3,
745 "", arbitrary_tenant, "example_bucket")),
747 EXPECT_EQ(denyp.eval(allowedIPv6, trueacct, s3ListBucket,
748 ARN(Partition::aws, Service::s3,
749 "", arbitrary_tenant, "example_bucket/myobject")),
752 EXPECT_EQ(fullp.eval(allowedIP, trueacct, s3ListBucket,
753 ARN(Partition::aws, Service::s3,
754 "", arbitrary_tenant, "example_bucket")),
756 EXPECT_EQ(fullp.eval(allowedIP, trueacct, s3ListBucket,
757 ARN(Partition::aws, Service::s3,
758 "", arbitrary_tenant, "example_bucket/myobject")),
761 EXPECT_EQ(fullp.eval(blacklistedIP, trueacct, s3ListBucket,
762 ARN(Partition::aws, Service::s3,
763 "", arbitrary_tenant, "example_bucket")),
765 EXPECT_EQ(fullp.eval(blacklistedIP, trueacct, s3ListBucket,
766 ARN(Partition::aws, Service::s3,
767 "", arbitrary_tenant, "example_bucket/myobject")),
770 EXPECT_EQ(fullp.eval(allowedIPv6, trueacct, s3ListBucket,
771 ARN(Partition::aws, Service::s3,
772 "", arbitrary_tenant, "example_bucket")),
774 EXPECT_EQ(fullp.eval(allowedIPv6, trueacct, s3ListBucket,
775 ARN(Partition::aws, Service::s3,
776 "", arbitrary_tenant, "example_bucket/myobject")),
779 EXPECT_EQ(fullp.eval(blacklistedIPv6, trueacct, s3ListBucket,
780 ARN(Partition::aws, Service::s3,
781 "", arbitrary_tenant, "example_bucket")),
783 EXPECT_EQ(fullp.eval(blacklistedIPv6, trueacct, s3ListBucket,
784 ARN(Partition::aws, Service::s3,
785 "", arbitrary_tenant, "example_bucket/myobject")),
789 string IPPolicyTest::ip_address_allow_example = R"(
791 "Version": "2012-10-17",
792 "Id": "S3SimpleIPPolicyTest",
796 "Principal": {"AWS": ["arn:aws:iam::ACCOUNT-ID-WITHOUT-HYPHENS:root"]},
797 "Action": "s3:ListBucket",
799 "arn:aws:s3:::example_bucket"
802 "IpAddress": {"aws:SourceIp": "192.168.1.0/24"}
808 string IPPolicyTest::ip_address_deny_example = R"(
810 "Version": "2012-10-17",
811 "Id": "S3IPPolicyTest",
815 "Action": "s3:ListBucket",
816 "Principal": {"AWS": ["arn:aws:iam::ACCOUNT-ID-WITHOUT-HYPHENS:root"]},
818 "arn:aws:s3:::example_bucket",
819 "arn:aws:s3:::example_bucket/*"
822 "NotIpAddress": {"aws:SourceIp": ["192.168.1.1/32", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"]}
828 string IPPolicyTest::ip_address_full_example = R"(
830 "Version": "2012-10-17",
831 "Id": "S3IPPolicyTest",
835 "Action": "s3:ListBucket",
838 "arn:aws:s3:::example_bucket",
839 "arn:aws:s3:::example_bucket/*"
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"]}
849 TEST(MatchWildcards, Simple)
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));
869 TEST(MatchWildcards, QuestionMark)
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));
893 TEST(MatchWildcards, Asterisk)
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));
930 TEST(MatchPolicy, Action)
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
939 TEST(MatchPolicy, Resource)
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
948 TEST(MatchPolicy, ARN)
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
957 TEST(MatchPolicy, String)
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