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