]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_iam_policy.cc
import ceph 16.2.6
[ceph.git] / ceph / src / rgw / rgw_iam_policy.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
3
4
5 #include <cstring>
6 #include <iostream>
7 #include <regex>
8 #include <sstream>
9 #include <stack>
10 #include <utility>
11
12 #include <experimental/iterator>
13
14 #include "rapidjson/reader.h"
15
16 #include "rgw_auth.h"
17 #include <arpa/inet.h>
18 #include "rgw_iam_policy.h"
19
20 namespace {
21 constexpr int dout_subsys = ceph_subsys_rgw;
22 }
23
24 using std::bitset;
25 using std::find;
26 using std::int64_t;
27 using std::move;
28 using std::pair;
29 using std::size_t;
30 using std::string;
31 using std::stringstream;
32 using std::ostream;
33 using std::uint16_t;
34 using std::uint64_t;
35 using std::unordered_map;
36
37 using boost::container::flat_set;
38 using std::regex;
39 using std::regex_constants::ECMAScript;
40 using std::regex_constants::optimize;
41 using std::regex_match;
42 using std::smatch;
43
44 using rapidjson::BaseReaderHandler;
45 using rapidjson::UTF8;
46 using rapidjson::SizeType;
47 using rapidjson::Reader;
48 using rapidjson::kParseCommentsFlag;
49 using rapidjson::kParseNumbersAsStringsFlag;
50 using rapidjson::StringStream;
51 using rapidjson::ParseResult;
52
53 using rgw::auth::Principal;
54
55 namespace rgw {
56 namespace IAM {
57 #include "rgw_iam_policy_keywords.frag.cc"
58
59 struct actpair {
60 const char* name;
61 const uint64_t bit;
62 };
63
64
65
66 static const actpair actpairs[] =
67 {{ "s3:AbortMultipartUpload", s3AbortMultipartUpload },
68 { "s3:CreateBucket", s3CreateBucket },
69 { "s3:DeleteBucketPolicy", s3DeleteBucketPolicy },
70 { "s3:DeleteBucket", s3DeleteBucket },
71 { "s3:DeleteBucketWebsite", s3DeleteBucketWebsite },
72 { "s3:DeleteObject", s3DeleteObject },
73 { "s3:DeleteObjectVersion", s3DeleteObjectVersion },
74 { "s3:DeleteObjectTagging", s3DeleteObjectTagging },
75 { "s3:DeleteObjectVersionTagging", s3DeleteObjectVersionTagging },
76 { "s3:DeleteBucketPublicAccessBlock", s3DeleteBucketPublicAccessBlock},
77 { "s3:DeletePublicAccessBlock", s3DeletePublicAccessBlock},
78 { "s3:DeleteReplicationConfiguration", s3DeleteReplicationConfiguration },
79 { "s3:GetAccelerateConfiguration", s3GetAccelerateConfiguration },
80 { "s3:GetBucketAcl", s3GetBucketAcl },
81 { "s3:GetBucketCORS", s3GetBucketCORS },
82 { "s3:GetBucketLocation", s3GetBucketLocation },
83 { "s3:GetBucketLogging", s3GetBucketLogging },
84 { "s3:GetBucketNotification", s3GetBucketNotification },
85 { "s3:GetBucketPolicy", s3GetBucketPolicy },
86 { "s3:GetBucketPolicyStatus", s3GetBucketPolicyStatus },
87 { "s3:GetBucketPublicAccessBlock", s3GetBucketPublicAccessBlock },
88 { "s3:GetBucketRequestPayment", s3GetBucketRequestPayment },
89 { "s3:GetBucketTagging", s3GetBucketTagging },
90 { "s3:GetBucketVersioning", s3GetBucketVersioning },
91 { "s3:GetBucketWebsite", s3GetBucketWebsite },
92 { "s3:GetLifecycleConfiguration", s3GetLifecycleConfiguration },
93 { "s3:GetBucketObjectLockConfiguration", s3GetBucketObjectLockConfiguration },
94 { "s3:GetPublicAccessBlock", s3GetPublicAccessBlock },
95 { "s3:GetObjectAcl", s3GetObjectAcl },
96 { "s3:GetObject", s3GetObject },
97 { "s3:GetObjectTorrent", s3GetObjectTorrent },
98 { "s3:GetObjectVersionAcl", s3GetObjectVersionAcl },
99 { "s3:GetObjectVersion", s3GetObjectVersion },
100 { "s3:GetObjectVersionTorrent", s3GetObjectVersionTorrent },
101 { "s3:GetObjectTagging", s3GetObjectTagging },
102 { "s3:GetObjectVersionTagging", s3GetObjectVersionTagging},
103 { "s3:GetObjectRetention", s3GetObjectRetention},
104 { "s3:GetObjectLegalHold", s3GetObjectLegalHold},
105 { "s3:GetReplicationConfiguration", s3GetReplicationConfiguration },
106 { "s3:ListAllMyBuckets", s3ListAllMyBuckets },
107 { "s3:ListBucketMultipartUploads", s3ListBucketMultipartUploads },
108 { "s3:ListBucket", s3ListBucket },
109 { "s3:ListBucketVersions", s3ListBucketVersions },
110 { "s3:ListMultipartUploadParts", s3ListMultipartUploadParts },
111 { "s3:PutAccelerateConfiguration", s3PutAccelerateConfiguration },
112 { "s3:PutBucketAcl", s3PutBucketAcl },
113 { "s3:PutBucketCORS", s3PutBucketCORS },
114 { "s3:PutBucketLogging", s3PutBucketLogging },
115 { "s3:PutBucketNotification", s3PutBucketNotification },
116 { "s3:PutBucketPolicy", s3PutBucketPolicy },
117 { "s3:PutBucketRequestPayment", s3PutBucketRequestPayment },
118 { "s3:PutBucketTagging", s3PutBucketTagging },
119 { "s3:PutBucketVersioning", s3PutBucketVersioning },
120 { "s3:PutBucketWebsite", s3PutBucketWebsite },
121 { "s3:PutLifecycleConfiguration", s3PutLifecycleConfiguration },
122 { "s3:PutBucketObjectLockConfiguration", s3PutBucketObjectLockConfiguration },
123 { "s3:PutObjectAcl", s3PutObjectAcl },
124 { "s3:PutObject", s3PutObject },
125 { "s3:PutObjectVersionAcl", s3PutObjectVersionAcl },
126 { "s3:PutObjectTagging", s3PutObjectTagging },
127 { "s3:PutObjectVersionTagging", s3PutObjectVersionTagging },
128 { "s3:PutObjectRetention", s3PutObjectRetention },
129 { "s3:PutObjectLegalHold", s3PutObjectLegalHold },
130 { "s3:BypassGovernanceRetention", s3BypassGovernanceRetention },
131 { "s3:PutBucketPublicAccessBlock", s3PutBucketPublicAccessBlock },
132 { "s3:PutPublicAccessBlock", s3PutPublicAccessBlock },
133 { "s3:PutReplicationConfiguration", s3PutReplicationConfiguration },
134 { "s3:RestoreObject", s3RestoreObject },
135 { "iam:PutUserPolicy", iamPutUserPolicy },
136 { "iam:GetUserPolicy", iamGetUserPolicy },
137 { "iam:DeleteUserPolicy", iamDeleteUserPolicy },
138 { "iam:ListUserPolicies", iamListUserPolicies },
139 { "iam:CreateRole", iamCreateRole},
140 { "iam:DeleteRole", iamDeleteRole},
141 { "iam:GetRole", iamGetRole},
142 { "iam:ModifyRole", iamModifyRole},
143 { "iam:ListRoles", iamListRoles},
144 { "iam:PutRolePolicy", iamPutRolePolicy},
145 { "iam:GetRolePolicy", iamGetRolePolicy},
146 { "iam:ListRolePolicies", iamListRolePolicies},
147 { "iam:DeleteRolePolicy", iamDeleteRolePolicy},
148 { "iam:CreateOIDCProvider", iamCreateOIDCProvider},
149 { "iam:DeleteOIDCProvider", iamDeleteOIDCProvider},
150 { "iam:GetOIDCProvider", iamGetOIDCProvider},
151 { "iam:ListOIDCProviders", iamListOIDCProviders},
152 { "sts:AssumeRole", stsAssumeRole},
153 { "sts:AssumeRoleWithWebIdentity", stsAssumeRoleWithWebIdentity},
154 { "sts:GetSessionToken", stsGetSessionToken},
155 };
156
157 struct PolicyParser;
158
159 const Keyword top[1]{"<Top>", TokenKind::pseudo, TokenID::Top, 0, false,
160 false};
161 const Keyword cond_key[1]{"<Condition Key>", TokenKind::cond_key,
162 TokenID::CondKey, 0, true, false};
163
164 struct ParseState {
165 PolicyParser* pp;
166 const Keyword* w;
167
168 bool arraying = false;
169 bool objecting = false;
170 bool cond_ifexists = false;
171
172 void reset();
173
174 ParseState(PolicyParser* pp, const Keyword* w)
175 : pp(pp), w(w) {}
176
177 bool obj_start();
178
179 bool obj_end();
180
181 bool array_start() {
182 if (w->arrayable && !arraying) {
183 arraying = true;
184 return true;
185 }
186 return false;
187 }
188
189 bool array_end();
190
191 bool key(const char* s, size_t l);
192 bool do_string(CephContext* cct, const char* s, size_t l);
193 bool number(const char* str, size_t l);
194 };
195
196 // If this confuses you, look up the Curiously Recurring Template Pattern
197 struct PolicyParser : public BaseReaderHandler<UTF8<>, PolicyParser> {
198 keyword_hash tokens;
199 std::vector<ParseState> s;
200 CephContext* cct;
201 const string& tenant;
202 Policy& policy;
203 uint32_t v = 0;
204
205 uint32_t seen = 0;
206
207 uint32_t dex(TokenID in) const {
208 switch (in) {
209 case TokenID::Version:
210 return 0x1;
211 case TokenID::Id:
212 return 0x2;
213 case TokenID::Statement:
214 return 0x4;
215 case TokenID::Sid:
216 return 0x8;
217 case TokenID::Effect:
218 return 0x10;
219 case TokenID::Principal:
220 return 0x20;
221 case TokenID::NotPrincipal:
222 return 0x40;
223 case TokenID::Action:
224 return 0x80;
225 case TokenID::NotAction:
226 return 0x100;
227 case TokenID::Resource:
228 return 0x200;
229 case TokenID::NotResource:
230 return 0x400;
231 case TokenID::Condition:
232 return 0x800;
233 case TokenID::AWS:
234 return 0x1000;
235 case TokenID::Federated:
236 return 0x2000;
237 case TokenID::Service:
238 return 0x4000;
239 case TokenID::CanonicalUser:
240 return 0x8000;
241 default:
242 ceph_abort();
243 }
244 }
245 bool test(TokenID in) {
246 return seen & dex(in);
247 }
248 void set(TokenID in) {
249 seen |= dex(in);
250 if (dex(in) & (dex(TokenID::Sid) | dex(TokenID::Effect) |
251 dex(TokenID::Principal) | dex(TokenID::NotPrincipal) |
252 dex(TokenID::Action) | dex(TokenID::NotAction) |
253 dex(TokenID::Resource) | dex(TokenID::NotResource) |
254 dex(TokenID::Condition) | dex(TokenID::AWS) |
255 dex(TokenID::Federated) | dex(TokenID::Service) |
256 dex(TokenID::CanonicalUser))) {
257 v |= dex(in);
258 }
259 }
260 void set(std::initializer_list<TokenID> l) {
261 for (auto in : l) {
262 seen |= dex(in);
263 if (dex(in) & (dex(TokenID::Sid) | dex(TokenID::Effect) |
264 dex(TokenID::Principal) | dex(TokenID::NotPrincipal) |
265 dex(TokenID::Action) | dex(TokenID::NotAction) |
266 dex(TokenID::Resource) | dex(TokenID::NotResource) |
267 dex(TokenID::Condition) | dex(TokenID::AWS) |
268 dex(TokenID::Federated) | dex(TokenID::Service) |
269 dex(TokenID::CanonicalUser))) {
270 v |= dex(in);
271 }
272 }
273 }
274 void reset(TokenID in) {
275 seen &= ~dex(in);
276 if (dex(in) & (dex(TokenID::Sid) | dex(TokenID::Effect) |
277 dex(TokenID::Principal) | dex(TokenID::NotPrincipal) |
278 dex(TokenID::Action) | dex(TokenID::NotAction) |
279 dex(TokenID::Resource) | dex(TokenID::NotResource) |
280 dex(TokenID::Condition) | dex(TokenID::AWS) |
281 dex(TokenID::Federated) | dex(TokenID::Service) |
282 dex(TokenID::CanonicalUser))) {
283 v &= ~dex(in);
284 }
285 }
286 void reset(std::initializer_list<TokenID> l) {
287 for (auto in : l) {
288 seen &= ~dex(in);
289 if (dex(in) & (dex(TokenID::Sid) | dex(TokenID::Effect) |
290 dex(TokenID::Principal) | dex(TokenID::NotPrincipal) |
291 dex(TokenID::Action) | dex(TokenID::NotAction) |
292 dex(TokenID::Resource) | dex(TokenID::NotResource) |
293 dex(TokenID::Condition) | dex(TokenID::AWS) |
294 dex(TokenID::Federated) | dex(TokenID::Service) |
295 dex(TokenID::CanonicalUser))) {
296 v &= ~dex(in);
297 }
298 }
299 }
300 void reset(uint32_t& v) {
301 seen &= ~v;
302 v = 0;
303 }
304
305 PolicyParser(CephContext* cct, const string& tenant, Policy& policy)
306 : cct(cct), tenant(tenant), policy(policy) {}
307 PolicyParser(const PolicyParser& policy) = delete;
308
309 bool StartObject() {
310 if (s.empty()) {
311 s.push_back({this, top});
312 s.back().objecting = true;
313 return true;
314 }
315
316 return s.back().obj_start();
317 }
318 bool EndObject(SizeType memberCount) {
319 if (s.empty()) {
320 return false;
321 }
322 return s.back().obj_end();
323 }
324 bool Key(const char* str, SizeType length, bool copy) {
325 if (s.empty()) {
326 return false;
327 }
328 return s.back().key(str, length);
329 }
330
331 bool String(const char* str, SizeType length, bool copy) {
332 if (s.empty()) {
333 return false;
334 }
335 return s.back().do_string(cct, str, length);
336 }
337 bool RawNumber(const char* str, SizeType length, bool copy) {
338 if (s.empty()) {
339 return false;
340 }
341
342 return s.back().number(str, length);
343 }
344 bool StartArray() {
345 if (s.empty()) {
346 return false;
347 }
348
349 return s.back().array_start();
350 }
351 bool EndArray(SizeType) {
352 if (s.empty()) {
353 return false;
354 }
355
356 return s.back().array_end();
357 }
358
359 bool Default() {
360 return false;
361 }
362 };
363
364
365 // I really despise this misfeature of C++.
366 //
367 bool ParseState::obj_end() {
368 if (objecting) {
369 objecting = false;
370 if (!arraying) {
371 pp->s.pop_back();
372 } else {
373 reset();
374 }
375 return true;
376 }
377 return false;
378 }
379
380 bool ParseState::key(const char* s, size_t l) {
381 auto token_len = l;
382 bool ifexists = false;
383 if (w->id == TokenID::Condition && w->kind == TokenKind::statement) {
384 static constexpr char IfExists[] = "IfExists";
385 if (boost::algorithm::ends_with(std::string_view{s, l}, IfExists)) {
386 ifexists = true;
387 token_len -= sizeof(IfExists)-1;
388 }
389 }
390 auto k = pp->tokens.lookup(s, token_len);
391
392 if (!k) {
393 if (w->kind == TokenKind::cond_op) {
394 auto id = w->id;
395 auto& t = pp->policy.statements.back();
396 auto c_ife = cond_ifexists;
397 pp->s.emplace_back(pp, cond_key);
398 t.conditions.emplace_back(id, s, l, c_ife);
399 return true;
400 } else {
401 return false;
402 }
403 }
404
405 // If the token we're going with belongs within the condition at the
406 // top of the stack and we haven't already encountered it, push it
407 // on the stack
408 // Top
409 if ((((w->id == TokenID::Top) && (k->kind == TokenKind::top)) ||
410 // Statement
411 ((w->id == TokenID::Statement) && (k->kind == TokenKind::statement)) ||
412
413 /// Principal
414 ((w->id == TokenID::Principal || w->id == TokenID::NotPrincipal) &&
415 (k->kind == TokenKind::princ_type))) &&
416
417 // Check that it hasn't been encountered. Note that this
418 // conjoins with the run of disjunctions above.
419 !pp->test(k->id)) {
420 pp->set(k->id);
421 pp->s.emplace_back(pp, k);
422 return true;
423 } else if ((w->id == TokenID::Condition) &&
424 (k->kind == TokenKind::cond_op)) {
425 pp->s.emplace_back(pp, k);
426 pp->s.back().cond_ifexists = ifexists;
427 return true;
428 }
429 return false;
430 }
431
432 // I should just rewrite a few helper functions to use iterators,
433 // which will make all of this ever so much nicer.
434 static boost::optional<Principal> parse_principal(CephContext* cct, TokenID t,
435 string&& s) {
436 // Wildcard!
437 if ((t == TokenID::AWS) && (s == "*")) {
438 return Principal::wildcard();
439
440 // Do nothing for now.
441 } else if (t == TokenID::CanonicalUser) {
442
443 } // AWS and Federated ARNs
444 else if (t == TokenID::AWS || t == TokenID::Federated) {
445 if (auto a = ARN::parse(s)) {
446 if (a->resource == "root") {
447 return Principal::tenant(std::move(a->account));
448 }
449
450 static const char rx_str[] = "([^/]*)/(.*)";
451 static const regex rx(rx_str, sizeof(rx_str) - 1,
452 std::regex_constants::ECMAScript |
453 std::regex_constants::optimize);
454 smatch match;
455 if (regex_match(a->resource, match, rx) && match.size() == 3) {
456 if (match[1] == "user") {
457 return Principal::user(std::move(a->account),
458 match[2]);
459 }
460
461 if (match[1] == "role") {
462 return Principal::role(std::move(a->account),
463 match[2]);
464 }
465
466 if (match[1] == "oidc-provider") {
467 return Principal::oidc_provider(std::move(match[2]));
468 }
469 if (match[1] == "assumed-role") {
470 return Principal::assumed_role(std::move(a->account), match[2]);
471 }
472 }
473 } else {
474 if (std::none_of(s.begin(), s.end(),
475 [](const char& c) {
476 return (c == ':') || (c == '/');
477 })) {
478 // Since tenants are simply prefixes, there's no really good
479 // way to see if one exists or not. So we return the thing and
480 // let them try to match against it.
481 return Principal::tenant(std::move(s));
482 }
483 }
484 }
485
486 ldout(cct, 0) << "Supplied principal is discarded: " << s << dendl;
487 return boost::none;
488 }
489
490 bool ParseState::do_string(CephContext* cct, const char* s, size_t l) {
491 auto k = pp->tokens.lookup(s, l);
492 Policy& p = pp->policy;
493 bool is_action = false;
494 bool is_validaction = false;
495 Statement* t = p.statements.empty() ? nullptr : &(p.statements.back());
496
497 // Top level!
498 if ((w->id == TokenID::Version) && k &&
499 k->kind == TokenKind::version_key) {
500 p.version = static_cast<Version>(k->specific);
501 } else if (w->id == TokenID::Id) {
502 p.id = string(s, l);
503
504 // Statement
505
506 } else if (w->id == TokenID::Sid) {
507 t->sid.emplace(s, l);
508 } else if ((w->id == TokenID::Effect) && k &&
509 k->kind == TokenKind::effect_key) {
510 t->effect = static_cast<Effect>(k->specific);
511 } else if (w->id == TokenID::Principal && s && *s == '*') {
512 t->princ.emplace(Principal::wildcard());
513 } else if (w->id == TokenID::NotPrincipal && s && *s == '*') {
514 t->noprinc.emplace(Principal::wildcard());
515 } else if ((w->id == TokenID::Action) ||
516 (w->id == TokenID::NotAction)) {
517 is_action = true;
518 if (*s == '*') {
519 is_validaction = true;
520 (w->id == TokenID::Action ?
521 t->action = allValue : t->notaction = allValue);
522 } else {
523 for (auto& p : actpairs) {
524 if (match_policy({s, l}, p.name, MATCH_POLICY_ACTION)) {
525 is_validaction = true;
526 (w->id == TokenID::Action ? t->action[p.bit] = 1 : t->notaction[p.bit] = 1);
527 }
528 if ((t->action & s3AllValue) == s3AllValue) {
529 t->action[s3All] = 1;
530 }
531 if ((t->notaction & s3AllValue) == s3AllValue) {
532 t->notaction[s3All] = 1;
533 }
534 if ((t->action & iamAllValue) == iamAllValue) {
535 t->action[iamAll] = 1;
536 }
537 if ((t->notaction & iamAllValue) == iamAllValue) {
538 t->notaction[iamAll] = 1;
539 }
540 if ((t->action & stsAllValue) == stsAllValue) {
541 t->action[stsAll] = 1;
542 }
543 if ((t->notaction & stsAllValue) == stsAllValue) {
544 t->notaction[stsAll] = 1;
545 }
546 }
547 }
548 } else if (w->id == TokenID::Resource || w->id == TokenID::NotResource) {
549 auto a = ARN::parse({s, l}, true);
550 // You can't specify resources for someone ELSE'S account.
551 if (a && (a->account.empty() || a->account == pp->tenant ||
552 a->account == "*")) {
553 if (a->account.empty() || a->account == "*")
554 a->account = pp->tenant;
555 (w->id == TokenID::Resource ? t->resource : t->notresource)
556 .emplace(std::move(*a));
557 }
558 else
559 ldout(cct, 0) << "Supplied resource is discarded: " << string(s, l)
560 << dendl;
561 } else if (w->kind == TokenKind::cond_key) {
562 auto& t = pp->policy.statements.back();
563 t.conditions.back().vals.emplace_back(s, l);
564
565 // Principals
566
567 } else if (w->kind == TokenKind::princ_type) {
568 if (pp->s.size() <= 1) {
569 return false;
570 }
571 auto& pri = pp->s[pp->s.size() - 2].w->id == TokenID::Principal ?
572 t->princ : t->noprinc;
573
574
575 if (auto o = parse_principal(pp->cct, w->id, string(s, l))) {
576 pri.emplace(std::move(*o));
577 }
578
579 // Failure
580
581 } else {
582 return false;
583 }
584
585 if (!arraying) {
586 pp->s.pop_back();
587 }
588
589 if (is_action && !is_validaction){
590 return false;
591 }
592
593 return true;
594 }
595
596 bool ParseState::number(const char* s, size_t l) {
597 // Top level!
598 if (w->kind == TokenKind::cond_key) {
599 auto& t = pp->policy.statements.back();
600 t.conditions.back().vals.emplace_back(s, l);
601
602 // Failure
603
604 } else {
605 return false;
606 }
607
608 if (!arraying) {
609 pp->s.pop_back();
610 }
611
612 return true;
613 }
614
615 void ParseState::reset() {
616 pp->reset(pp->v);
617 }
618
619 bool ParseState::obj_start() {
620 if (w->objectable && !objecting) {
621 objecting = true;
622 if (w->id == TokenID::Statement) {
623 pp->policy.statements.emplace_back();
624 }
625
626 return true;
627 }
628
629 return false;
630 }
631
632
633 bool ParseState::array_end() {
634 if (arraying && !objecting) {
635 pp->s.pop_back();
636 return true;
637 }
638
639 return false;
640 }
641
642 ostream& operator <<(ostream& m, const MaskedIP& ip) {
643 // I have a theory about why std::bitset is the way it is.
644 if (ip.v6) {
645 for (int i = 7; i >= 0; --i) {
646 uint16_t hextet = 0;
647 for (int j = 15; j >= 0; --j) {
648 hextet |= (ip.addr[(i * 16) + j] << j);
649 }
650 m << hex << (unsigned int) hextet;
651 if (i != 0) {
652 m << ":";
653 }
654 }
655 } else {
656 // It involves Satan.
657 for (int i = 3; i >= 0; --i) {
658 uint8_t b = 0;
659 for (int j = 7; j >= 0; --j) {
660 b |= (ip.addr[(i * 8) + j] << j);
661 }
662 m << (unsigned int) b;
663 if (i != 0) {
664 m << ".";
665 }
666 }
667 }
668 m << "/" << dec << ip.prefix;
669 // It would explain a lot
670 return m;
671 }
672
673 bool Condition::eval(const Environment& env) const {
674 auto i = env.find(key);
675 if (op == TokenID::Null) {
676 return i == env.end() ? true : false;
677 }
678
679 if (i == env.end()) {
680 return ifexists;
681 }
682 const auto& s = i->second;
683
684 switch (op) {
685 // String!
686 case TokenID::StringEquals:
687 return orrible(std::equal_to<std::string>(), s, vals);
688
689 case TokenID::StringNotEquals:
690 return orrible(std::not_fn(std::equal_to<std::string>()),
691 s, vals);
692
693 case TokenID::StringEqualsIgnoreCase:
694 return orrible(ci_equal_to(), s, vals);
695
696 case TokenID::StringNotEqualsIgnoreCase:
697 return orrible(std::not_fn(ci_equal_to()), s, vals);
698
699 case TokenID::StringLike:
700 return orrible(string_like(), s, vals);
701
702 case TokenID::StringNotLike:
703 return orrible(std::not_fn(string_like()), s, vals);
704
705 // Numeric
706 case TokenID::NumericEquals:
707 return shortible(std::equal_to<double>(), as_number, s, vals);
708
709 case TokenID::NumericNotEquals:
710 return shortible(std::not_fn(std::equal_to<double>()),
711 as_number, s, vals);
712
713
714 case TokenID::NumericLessThan:
715 return shortible(std::less<double>(), as_number, s, vals);
716
717
718 case TokenID::NumericLessThanEquals:
719 return shortible(std::less_equal<double>(), as_number, s, vals);
720
721 case TokenID::NumericGreaterThan:
722 return shortible(std::greater<double>(), as_number, s, vals);
723
724 case TokenID::NumericGreaterThanEquals:
725 return shortible(std::greater_equal<double>(), as_number, s, vals);
726
727 // Date!
728 case TokenID::DateEquals:
729 return shortible(std::equal_to<ceph::real_time>(), as_date, s, vals);
730
731 case TokenID::DateNotEquals:
732 return shortible(std::not_fn(std::equal_to<ceph::real_time>()),
733 as_date, s, vals);
734
735 case TokenID::DateLessThan:
736 return shortible(std::less<ceph::real_time>(), as_date, s, vals);
737
738
739 case TokenID::DateLessThanEquals:
740 return shortible(std::less_equal<ceph::real_time>(), as_date, s, vals);
741
742 case TokenID::DateGreaterThan:
743 return shortible(std::greater<ceph::real_time>(), as_date, s, vals);
744
745 case TokenID::DateGreaterThanEquals:
746 return shortible(std::greater_equal<ceph::real_time>(), as_date, s,
747 vals);
748
749 // Bool!
750 case TokenID::Bool:
751 return shortible(std::equal_to<bool>(), as_bool, s, vals);
752
753 // Binary!
754 case TokenID::BinaryEquals:
755 return shortible(std::equal_to<ceph::bufferlist>(), as_binary, s,
756 vals);
757
758 // IP Address!
759 case TokenID::IpAddress:
760 return shortible(std::equal_to<MaskedIP>(), as_network, s, vals);
761
762 case TokenID::NotIpAddress:
763 {
764 auto xc = as_network(s);
765 if (!xc) {
766 return false;
767 }
768
769 for (const string& d : vals) {
770 auto xd = as_network(d);
771 if (!xd) {
772 continue;
773 }
774
775 if (xc == xd) {
776 return false;
777 }
778 }
779 return true;
780 }
781
782 #if 0
783 // Amazon Resource Names! (Does S3 need this?)
784 TokenID::ArnEquals, TokenID::ArnNotEquals, TokenID::ArnLike,
785 TokenID::ArnNotLike,
786 #endif
787
788 default:
789 return false;
790 }
791 }
792
793 boost::optional<MaskedIP> Condition::as_network(const string& s) {
794 MaskedIP m;
795 if (s.empty()) {
796 return boost::none;
797 }
798
799 m.v6 = (s.find(':') == string::npos) ? false : true;
800
801 auto slash = s.find('/');
802 if (slash == string::npos) {
803 m.prefix = m.v6 ? 128 : 32;
804 } else {
805 char* end = 0;
806 m.prefix = strtoul(s.data() + slash + 1, &end, 10);
807 if (*end != 0 || (m.v6 && m.prefix > 128) ||
808 (!m.v6 && m.prefix > 32)) {
809 return boost::none;
810 }
811 }
812
813 string t;
814 auto p = &s;
815
816 if (slash != string::npos) {
817 t.assign(s, 0, slash);
818 p = &t;
819 }
820
821 if (m.v6) {
822 struct in6_addr a;
823 if (inet_pton(AF_INET6, p->c_str(), static_cast<void*>(&a)) != 1) {
824 return boost::none;
825 }
826
827 m.addr |= Address(a.s6_addr[15]) << 0;
828 m.addr |= Address(a.s6_addr[14]) << 8;
829 m.addr |= Address(a.s6_addr[13]) << 16;
830 m.addr |= Address(a.s6_addr[12]) << 24;
831 m.addr |= Address(a.s6_addr[11]) << 32;
832 m.addr |= Address(a.s6_addr[10]) << 40;
833 m.addr |= Address(a.s6_addr[9]) << 48;
834 m.addr |= Address(a.s6_addr[8]) << 56;
835 m.addr |= Address(a.s6_addr[7]) << 64;
836 m.addr |= Address(a.s6_addr[6]) << 72;
837 m.addr |= Address(a.s6_addr[5]) << 80;
838 m.addr |= Address(a.s6_addr[4]) << 88;
839 m.addr |= Address(a.s6_addr[3]) << 96;
840 m.addr |= Address(a.s6_addr[2]) << 104;
841 m.addr |= Address(a.s6_addr[1]) << 112;
842 m.addr |= Address(a.s6_addr[0]) << 120;
843 } else {
844 struct in_addr a;
845 if (inet_pton(AF_INET, p->c_str(), static_cast<void*>(&a)) != 1) {
846 return boost::none;
847 }
848
849 m.addr = ntohl(a.s_addr);
850 }
851
852 return m;
853 }
854
855 namespace {
856 const char* condop_string(const TokenID t) {
857 switch (t) {
858 case TokenID::StringEquals:
859 return "StringEquals";
860
861 case TokenID::StringNotEquals:
862 return "StringNotEquals";
863
864 case TokenID::StringEqualsIgnoreCase:
865 return "StringEqualsIgnoreCase";
866
867 case TokenID::StringNotEqualsIgnoreCase:
868 return "StringNotEqualsIgnoreCase";
869
870 case TokenID::StringLike:
871 return "StringLike";
872
873 case TokenID::StringNotLike:
874 return "StringNotLike";
875
876 // Numeric!
877 case TokenID::NumericEquals:
878 return "NumericEquals";
879
880 case TokenID::NumericNotEquals:
881 return "NumericNotEquals";
882
883 case TokenID::NumericLessThan:
884 return "NumericLessThan";
885
886 case TokenID::NumericLessThanEquals:
887 return "NumericLessThanEquals";
888
889 case TokenID::NumericGreaterThan:
890 return "NumericGreaterThan";
891
892 case TokenID::NumericGreaterThanEquals:
893 return "NumericGreaterThanEquals";
894
895 case TokenID::DateEquals:
896 return "DateEquals";
897
898 case TokenID::DateNotEquals:
899 return "DateNotEquals";
900
901 case TokenID::DateLessThan:
902 return "DateLessThan";
903
904 case TokenID::DateLessThanEquals:
905 return "DateLessThanEquals";
906
907 case TokenID::DateGreaterThan:
908 return "DateGreaterThan";
909
910 case TokenID::DateGreaterThanEquals:
911 return "DateGreaterThanEquals";
912
913 case TokenID::Bool:
914 return "Bool";
915
916 case TokenID::BinaryEquals:
917 return "BinaryEquals";
918
919 case TokenID::IpAddress:
920 return "case TokenID::IpAddress";
921
922 case TokenID::NotIpAddress:
923 return "NotIpAddress";
924
925 case TokenID::ArnEquals:
926 return "ArnEquals";
927
928 case TokenID::ArnNotEquals:
929 return "ArnNotEquals";
930
931 case TokenID::ArnLike:
932 return "ArnLike";
933
934 case TokenID::ArnNotLike:
935 return "ArnNotLike";
936
937 case TokenID::Null:
938 return "Null";
939
940 default:
941 return "InvalidConditionOperator";
942 }
943 }
944
945 template<typename Iterator>
946 ostream& print_array(ostream& m, Iterator begin, Iterator end) {
947 if (begin == end) {
948 m << "[]";
949 } else {
950 m << "[ ";
951 std::copy(begin, end, std::experimental::make_ostream_joiner(m, ", "));
952 m << " ]";
953 }
954 return m;
955 }
956
957 template<typename Iterator>
958 ostream& print_dict(ostream& m, Iterator begin, Iterator end) {
959 m << "{ ";
960 std::copy(begin, end, std::experimental::make_ostream_joiner(m, ", "));
961 m << " }";
962 return m;
963 }
964
965 }
966
967 ostream& operator <<(ostream& m, const Condition& c) {
968 m << condop_string(c.op);
969 if (c.ifexists) {
970 m << "IfExists";
971 }
972 m << ": { " << c.key;
973 print_array(m, c.vals.cbegin(), c.vals.cend());
974 return m << " }";
975 }
976
977 Effect Statement::eval(const Environment& e,
978 boost::optional<const rgw::auth::Identity&> ida,
979 uint64_t act, const ARN& res, boost::optional<PolicyPrincipal&> princ_type) const {
980
981 if (eval_principal(e, ida, princ_type) == Effect::Deny) {
982 return Effect::Pass;
983 }
984
985 if (!resource.empty()) {
986 if (!std::any_of(resource.begin(), resource.end(),
987 [&res](const ARN& pattern) {
988 return pattern.match(res);
989 })) {
990 return Effect::Pass;
991 }
992 } else if (!notresource.empty()) {
993 if (std::any_of(notresource.begin(), notresource.end(),
994 [&res](const ARN& pattern) {
995 return pattern.match(res);
996 })) {
997 return Effect::Pass;
998 }
999 }
1000
1001 if (!(action[act] == 1) || (notaction[act] == 1)) {
1002 return Effect::Pass;
1003 }
1004
1005 if (std::all_of(conditions.begin(),
1006 conditions.end(),
1007 [&e](const Condition& c) { return c.eval(e);})) {
1008 return effect;
1009 }
1010
1011 return Effect::Pass;
1012 }
1013
1014 Effect Statement::eval_principal(const Environment& e,
1015 boost::optional<const rgw::auth::Identity&> ida, boost::optional<PolicyPrincipal&> princ_type) const {
1016 if (princ_type) {
1017 *princ_type = PolicyPrincipal::Other;
1018 }
1019 if (ida) {
1020 if (princ.empty() && noprinc.empty()) {
1021 return Effect::Deny;
1022 }
1023 if (ida->get_identity_type() != TYPE_ROLE && !princ.empty() && !ida->is_identity(princ)) {
1024 return Effect::Deny;
1025 }
1026 if (ida->get_identity_type() == TYPE_ROLE && !princ.empty()) {
1027 bool princ_matched = false;
1028 for (auto p : princ) { // Check each principal to determine the type of the one that has matched
1029 boost::container::flat_set<Principal> id;
1030 id.insert(p);
1031 if (ida->is_identity(id)) {
1032 if (p.is_assumed_role() || p.is_user()) {
1033 if (princ_type) *princ_type = PolicyPrincipal::Session;
1034 } else {
1035 if (princ_type) *princ_type = PolicyPrincipal::Role;
1036 }
1037 princ_matched = true;
1038 }
1039 }
1040 if (!princ_matched) {
1041 return Effect::Deny;
1042 }
1043 } else if (!noprinc.empty() && ida->is_identity(noprinc)) {
1044 return Effect::Deny;
1045 }
1046 }
1047 return Effect::Allow;
1048 }
1049
1050 Effect Statement::eval_conditions(const Environment& e) const {
1051 if (std::all_of(conditions.begin(),
1052 conditions.end(),
1053 [&e](const Condition& c) { return c.eval(e);})) {
1054 return Effect::Allow;
1055 }
1056 return Effect::Deny;
1057 }
1058
1059 namespace {
1060 const char* action_bit_string(uint64_t action) {
1061 switch (action) {
1062 case s3GetObject:
1063 return "s3:GetObject";
1064
1065 case s3GetObjectVersion:
1066 return "s3:GetObjectVersion";
1067
1068 case s3PutObject:
1069 return "s3:PutObject";
1070
1071 case s3GetObjectAcl:
1072 return "s3:GetObjectAcl";
1073
1074 case s3GetObjectVersionAcl:
1075 return "s3:GetObjectVersionAcl";
1076
1077 case s3PutObjectAcl:
1078 return "s3:PutObjectAcl";
1079
1080 case s3PutObjectVersionAcl:
1081 return "s3:PutObjectVersionAcl";
1082
1083 case s3DeleteObject:
1084 return "s3:DeleteObject";
1085
1086 case s3DeleteObjectVersion:
1087 return "s3:DeleteObjectVersion";
1088
1089 case s3ListMultipartUploadParts:
1090 return "s3:ListMultipartUploadParts";
1091
1092 case s3AbortMultipartUpload:
1093 return "s3:AbortMultipartUpload";
1094
1095 case s3GetObjectTorrent:
1096 return "s3:GetObjectTorrent";
1097
1098 case s3GetObjectVersionTorrent:
1099 return "s3:GetObjectVersionTorrent";
1100
1101 case s3RestoreObject:
1102 return "s3:RestoreObject";
1103
1104 case s3CreateBucket:
1105 return "s3:CreateBucket";
1106
1107 case s3DeleteBucket:
1108 return "s3:DeleteBucket";
1109
1110 case s3ListBucket:
1111 return "s3:ListBucket";
1112
1113 case s3ListBucketVersions:
1114 return "s3:ListBucketVersions";
1115 case s3ListAllMyBuckets:
1116 return "s3:ListAllMyBuckets";
1117
1118 case s3ListBucketMultipartUploads:
1119 return "s3:ListBucketMultipartUploads";
1120
1121 case s3GetAccelerateConfiguration:
1122 return "s3:GetAccelerateConfiguration";
1123
1124 case s3PutAccelerateConfiguration:
1125 return "s3:PutAccelerateConfiguration";
1126
1127 case s3GetBucketAcl:
1128 return "s3:GetBucketAcl";
1129
1130 case s3PutBucketAcl:
1131 return "s3:PutBucketAcl";
1132
1133 case s3GetBucketCORS:
1134 return "s3:GetBucketCORS";
1135
1136 case s3PutBucketCORS:
1137 return "s3:PutBucketCORS";
1138
1139 case s3GetBucketVersioning:
1140 return "s3:GetBucketVersioning";
1141
1142 case s3PutBucketVersioning:
1143 return "s3:PutBucketVersioning";
1144
1145 case s3GetBucketRequestPayment:
1146 return "s3:GetBucketRequestPayment";
1147
1148 case s3PutBucketRequestPayment:
1149 return "s3:PutBucketRequestPayment";
1150
1151 case s3GetBucketLocation:
1152 return "s3:GetBucketLocation";
1153
1154 case s3GetBucketPolicy:
1155 return "s3:GetBucketPolicy";
1156
1157 case s3DeleteBucketPolicy:
1158 return "s3:DeleteBucketPolicy";
1159
1160 case s3PutBucketPolicy:
1161 return "s3:PutBucketPolicy";
1162
1163 case s3GetBucketNotification:
1164 return "s3:GetBucketNotification";
1165
1166 case s3PutBucketNotification:
1167 return "s3:PutBucketNotification";
1168
1169 case s3GetBucketLogging:
1170 return "s3:GetBucketLogging";
1171
1172 case s3PutBucketLogging:
1173 return "s3:PutBucketLogging";
1174
1175 case s3GetBucketTagging:
1176 return "s3:GetBucketTagging";
1177
1178 case s3PutBucketTagging:
1179 return "s3:PutBucketTagging";
1180
1181 case s3GetBucketWebsite:
1182 return "s3:GetBucketWebsite";
1183
1184 case s3PutBucketWebsite:
1185 return "s3:PutBucketWebsite";
1186
1187 case s3DeleteBucketWebsite:
1188 return "s3:DeleteBucketWebsite";
1189
1190 case s3GetLifecycleConfiguration:
1191 return "s3:GetLifecycleConfiguration";
1192
1193 case s3PutLifecycleConfiguration:
1194 return "s3:PutLifecycleConfiguration";
1195
1196 case s3PutReplicationConfiguration:
1197 return "s3:PutReplicationConfiguration";
1198
1199 case s3GetReplicationConfiguration:
1200 return "s3:GetReplicationConfiguration";
1201
1202 case s3DeleteReplicationConfiguration:
1203 return "s3:DeleteReplicationConfiguration";
1204
1205 case s3PutObjectTagging:
1206 return "s3:PutObjectTagging";
1207
1208 case s3PutObjectVersionTagging:
1209 return "s3:PutObjectVersionTagging";
1210
1211 case s3GetObjectTagging:
1212 return "s3:GetObjectTagging";
1213
1214 case s3GetObjectVersionTagging:
1215 return "s3:GetObjectVersionTagging";
1216
1217 case s3DeleteObjectTagging:
1218 return "s3:DeleteObjectTagging";
1219
1220 case s3DeleteObjectVersionTagging:
1221 return "s3:DeleteObjectVersionTagging";
1222
1223 case s3PutBucketObjectLockConfiguration:
1224 return "s3:PutBucketObjectLockConfiguration";
1225
1226 case s3GetBucketObjectLockConfiguration:
1227 return "s3:GetBucketObjectLockConfiguration";
1228
1229 case s3PutObjectRetention:
1230 return "s3:PutObjectRetention";
1231
1232 case s3GetObjectRetention:
1233 return "s3:GetObjectRetention";
1234
1235 case s3PutObjectLegalHold:
1236 return "s3:PutObjectLegalHold";
1237
1238 case s3GetObjectLegalHold:
1239 return "s3:GetObjectLegalHold";
1240
1241 case s3BypassGovernanceRetention:
1242 return "s3:BypassGovernanceRetention";
1243
1244 case iamPutUserPolicy:
1245 return "iam:PutUserPolicy";
1246
1247 case iamGetUserPolicy:
1248 return "iam:GetUserPolicy";
1249
1250 case iamListUserPolicies:
1251 return "iam:ListUserPolicies";
1252
1253 case iamDeleteUserPolicy:
1254 return "iam:DeleteUserPolicy";
1255
1256 case iamCreateRole:
1257 return "iam:CreateRole";
1258
1259 case iamDeleteRole:
1260 return "iam:DeleteRole";
1261
1262 case iamGetRole:
1263 return "iam:GetRole";
1264
1265 case iamModifyRole:
1266 return "iam:ModifyRole";
1267
1268 case iamListRoles:
1269 return "iam:ListRoles";
1270
1271 case iamPutRolePolicy:
1272 return "iam:PutRolePolicy";
1273
1274 case iamGetRolePolicy:
1275 return "iam:GetRolePolicy";
1276
1277 case iamListRolePolicies:
1278 return "iam:ListRolePolicies";
1279
1280 case iamDeleteRolePolicy:
1281 return "iam:DeleteRolePolicy";
1282
1283 case iamCreateOIDCProvider:
1284 return "iam:CreateOIDCProvider";
1285
1286 case iamDeleteOIDCProvider:
1287 return "iam:DeleteOIDCProvider";
1288
1289 case iamGetOIDCProvider:
1290 return "iam:GetOIDCProvider";
1291
1292 case iamListOIDCProviders:
1293 return "iam:ListOIDCProviders";
1294
1295 case stsAssumeRole:
1296 return "sts:AssumeRole";
1297
1298 case stsAssumeRoleWithWebIdentity:
1299 return "sts:AssumeRoleWithWebIdentity";
1300
1301 case stsGetSessionToken:
1302 return "sts:GetSessionToken";
1303 }
1304 return "s3Invalid";
1305 }
1306
1307 ostream& print_actions(ostream& m, const Action_t a) {
1308 bool begun = false;
1309 m << "[ ";
1310 for (auto i = 0U; i < allCount; ++i) {
1311 if (a[i] == 1) {
1312 if (begun) {
1313 m << ", ";
1314 } else {
1315 begun = true;
1316 }
1317 m << action_bit_string(i);
1318 }
1319 }
1320 if (begun) {
1321 m << " ]";
1322 } else {
1323 m << "]";
1324 }
1325 return m;
1326 }
1327 }
1328
1329 ostream& operator <<(ostream& m, const Statement& s) {
1330 m << "{ ";
1331 if (s.sid) {
1332 m << "Sid: " << *s.sid << ", ";
1333 }
1334 if (!s.princ.empty()) {
1335 m << "Principal: ";
1336 print_dict(m, s.princ.cbegin(), s.princ.cend());
1337 m << ", ";
1338 }
1339 if (!s.noprinc.empty()) {
1340 m << "NotPrincipal: ";
1341 print_dict(m, s.noprinc.cbegin(), s.noprinc.cend());
1342 m << ", ";
1343 }
1344
1345 m << "Effect: " <<
1346 (s.effect == Effect::Allow ?
1347 (const char*) "Allow" :
1348 (const char*) "Deny");
1349
1350 if (s.action.any() || s.notaction.any() || !s.resource.empty() ||
1351 !s.notresource.empty() || !s.conditions.empty()) {
1352 m << ", ";
1353 }
1354
1355 if (s.action.any()) {
1356 m << "Action: ";
1357 print_actions(m, s.action);
1358
1359 if (s.notaction.any() || !s.resource.empty() ||
1360 !s.notresource.empty() || !s.conditions.empty()) {
1361 m << ", ";
1362 }
1363 }
1364
1365 if (s.notaction.any()) {
1366 m << "NotAction: ";
1367 print_actions(m, s.notaction);
1368
1369 if (!s.resource.empty() || !s.notresource.empty() ||
1370 !s.conditions.empty()) {
1371 m << ", ";
1372 }
1373 }
1374
1375 if (!s.resource.empty()) {
1376 m << "Resource: ";
1377 print_array(m, s.resource.cbegin(), s.resource.cend());
1378
1379 if (!s.notresource.empty() || !s.conditions.empty()) {
1380 m << ", ";
1381 }
1382 }
1383
1384 if (!s.notresource.empty()) {
1385 m << "NotResource: ";
1386 print_array(m, s.notresource.cbegin(), s.notresource.cend());
1387
1388 if (!s.conditions.empty()) {
1389 m << ", ";
1390 }
1391 }
1392
1393 if (!s.conditions.empty()) {
1394 m << "Condition: ";
1395 print_dict(m, s.conditions.cbegin(), s.conditions.cend());
1396 }
1397
1398 return m << " }";
1399 }
1400
1401 Policy::Policy(CephContext* cct, const string& tenant,
1402 const bufferlist& _text)
1403 : text(_text.to_str()) {
1404 StringStream ss(text.data());
1405 PolicyParser pp(cct, tenant, *this);
1406 auto pr = Reader{}.Parse<kParseNumbersAsStringsFlag |
1407 kParseCommentsFlag>(ss, pp);
1408 if (!pr) {
1409 throw PolicyParseException(std::move(pr));
1410 }
1411 }
1412
1413 Effect Policy::eval(const Environment& e,
1414 boost::optional<const rgw::auth::Identity&> ida,
1415 std::uint64_t action, const ARN& resource,
1416 boost::optional<PolicyPrincipal&> princ_type) const {
1417 auto allowed = false;
1418 for (auto& s : statements) {
1419 auto g = s.eval(e, ida, action, resource, princ_type);
1420 if (g == Effect::Deny) {
1421 return g;
1422 } else if (g == Effect::Allow) {
1423 allowed = true;
1424 }
1425 }
1426 return allowed ? Effect::Allow : Effect::Pass;
1427 }
1428
1429 Effect Policy::eval_principal(const Environment& e,
1430 boost::optional<const rgw::auth::Identity&> ida, boost::optional<PolicyPrincipal&> princ_type) const {
1431 auto allowed = false;
1432 for (auto& s : statements) {
1433 auto g = s.eval_principal(e, ida, princ_type);
1434 if (g == Effect::Deny) {
1435 return g;
1436 } else if (g == Effect::Allow) {
1437 allowed = true;
1438 }
1439 }
1440 return allowed ? Effect::Allow : Effect::Deny;
1441 }
1442
1443 Effect Policy::eval_conditions(const Environment& e) const {
1444 auto allowed = false;
1445 for (auto& s : statements) {
1446 auto g = s.eval_conditions(e);
1447 if (g == Effect::Deny) {
1448 return g;
1449 } else if (g == Effect::Allow) {
1450 allowed = true;
1451 }
1452 }
1453 return allowed ? Effect::Allow : Effect::Deny;
1454 }
1455
1456 ostream& operator <<(ostream& m, const Policy& p) {
1457 m << "{ Version: "
1458 << (p.version == Version::v2008_10_17 ? "2008-10-17" : "2012-10-17");
1459
1460 if (p.id || !p.statements.empty()) {
1461 m << ", ";
1462 }
1463
1464 if (p.id) {
1465 m << "Id: " << *p.id;
1466 if (!p.statements.empty()) {
1467 m << ", ";
1468 }
1469 }
1470
1471 if (!p.statements.empty()) {
1472 m << "Statements: ";
1473 print_array(m, p.statements.cbegin(), p.statements.cend());
1474 m << ", ";
1475 }
1476 return m << " }";
1477 }
1478
1479 static const Environment iam_all_env = {
1480 {"aws:SourceIp","1.1.1.1"},
1481 {"aws:UserId","anonymous"},
1482 {"s3:x-amz-server-side-encryption-aws-kms-key-id","secret"}
1483 };
1484
1485 struct IsPublicStatement
1486 {
1487 bool operator() (const Statement &s) const {
1488 if (s.effect == Effect::Allow) {
1489 for (const auto& p : s.princ) {
1490 if (p.is_wildcard()) {
1491 return s.eval_conditions(iam_all_env) == Effect::Allow;
1492 }
1493 }
1494 // no princ should not contain fixed values
1495 return std::none_of(s.noprinc.begin(), s.noprinc.end(), [](const rgw::auth::Principal& p) {
1496 return p.is_wildcard();
1497 });
1498 }
1499 return false;
1500 }
1501 };
1502
1503
1504 bool is_public(const Policy& p)
1505 {
1506 return std::any_of(p.statements.begin(), p.statements.end(), IsPublicStatement());
1507 }
1508
1509 } // namespace IAM
1510 } // namespace rgw