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