1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
12 #include <arpa/inet.h>
14 #include <experimental/iterator>
16 #include "rapidjson/reader.h"
18 #include "include/expected.hpp"
21 #include "rgw_iam_policy.h"
25 constexpr int dout_subsys
= ceph_subsys_rgw
;
33 using std::stringstream
;
38 using boost::container::flat_set
;
40 using std::regex_match
;
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
;
51 using rgw::auth::Principal
;
55 #include "rgw_iam_policy_keywords.frag.cc"
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
},
164 const Keyword top
[1]{{"<Top>", TokenKind::pseudo
, TokenID::Top
, 0, false,
166 const Keyword cond_key
[1]{{"<Condition Key>", TokenKind::cond_key
,
167 TokenID::CondKey
, 0, true, false}};
173 bool arraying
= false;
174 bool objecting
= false;
175 bool cond_ifexists
= false;
179 void annotate(std::string
&& a
);
181 boost::optional
<Principal
> parse_principal(string
&& s
, string
* errmsg
);
183 ParseState(PolicyParser
* pp
, const Keyword
* w
)
191 if (w
->arrayable
&& !arraying
) {
195 annotate(fmt::format("`{}` does not take array.",
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
);
207 // If this confuses you, look up the Curiously Recurring Template Pattern
208 struct PolicyParser
: public BaseReaderHandler
<UTF8
<>, PolicyParser
> {
210 std::vector
<ParseState
> s
;
212 const string
& tenant
;
216 const bool reject_invalid_principals
;
220 std::string annotation
{"No error?"};
222 uint32_t dex(TokenID in
) const {
224 case TokenID::Version
:
228 case TokenID::Statement
:
232 case TokenID::Effect
:
234 case TokenID::Principal
:
236 case TokenID::NotPrincipal
:
238 case TokenID::Action
:
240 case TokenID::NotAction
:
242 case TokenID::Resource
:
244 case TokenID::NotResource
:
246 case TokenID::Condition
:
250 case TokenID::Federated
:
252 case TokenID::Service
:
254 case TokenID::CanonicalUser
:
260 bool test(TokenID in
) {
261 return seen
& dex(in
);
263 void set(TokenID 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
))) {
275 void set(std::initializer_list
<TokenID
> l
) {
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
))) {
289 void reset(TokenID 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
))) {
301 void reset(std::initializer_list
<TokenID
> l
) {
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
))) {
315 void reset(uint32_t& v
) {
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;
328 s
.push_back({this, top
});
329 s
.back().objecting
= true;
333 return s
.back().obj_start();
335 bool EndObject(SizeType memberCount
) {
337 annotation
= "Attempt to end unopened object at top level.";
340 return s
.back().obj_end();
342 bool Key(const char* str
, SizeType length
, bool copy
) {
344 annotation
= "Key not allowed at top level.";
347 return s
.back().key(str
, length
);
350 bool String(const char* str
, SizeType length
, bool copy
) {
352 annotation
= "String not allowed at top level.";
355 return s
.back().do_string(cct
, str
, length
);
357 bool RawNumber(const char* str
, SizeType length
, bool copy
) {
359 annotation
= "Number not allowed at top level.";
363 return s
.back().number(str
, length
);
367 annotation
= "Array not allowed at top level.";
371 return s
.back().array_start();
373 bool EndArray(SizeType
) {
378 return s
.back().array_end();
387 // I really despise this misfeature of C++.
389 void ParseState::annotate(std::string
&& a
) {
390 pp
->annotation
= std::move(a
);
393 bool ParseState::obj_end() {
404 fmt::format("Attempt to end unopened object on keyword `{}`.",
409 bool ParseState::key(const char* s
, size_t 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
)) {
416 token_len
-= sizeof(IfExists
)-1;
419 auto k
= pp
->tokens
.lookup(s
, token_len
);
422 if (w
->kind
== TokenKind::cond_op
) {
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
);
430 annotate(fmt::format("Unknown key `{}`.", std::string_view
{s
, token_len
}));
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
439 if ((((w
->id
== TokenID::Top
) && (k
->kind
== TokenKind::top
)) ||
441 ((w
->id
== TokenID::Statement
) && (k
->kind
== TokenKind::statement
)) ||
444 ((w
->id
== TokenID::Principal
|| w
->id
== TokenID::NotPrincipal
) &&
445 (k
->kind
== TokenKind::princ_type
))) &&
447 // Check that it hasn't been encountered. Note that this
448 // conjoins with the run of disjunctions above.
451 pp
->s
.emplace_back(pp
, k
);
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
;
459 annotate(fmt::format("Token `{}` is not allowed in the context of `{}`.",
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
,
468 if ((w
->id
== TokenID::AWS
) && (s
== "*")) {
470 return Principal::wildcard();
471 } else if (w
->id
== TokenID::CanonicalUser
) {
472 // Do nothing for now.
474 *errmsg
= "RGW does not support canonical users.";
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
));
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
);
488 if (regex_match(a
->resource
, match
, rx
) && match
.size() == 3) {
489 if (match
[1] == "user") {
490 return Principal::user(std::move(a
->account
),
494 if (match
[1] == "role") {
495 return Principal::role(std::move(a
->account
),
499 if (match
[1] == "oidc-provider") {
500 return Principal::oidc_provider(std::move(match
[2]));
502 if (match
[1] == "assumed-role") {
503 return Principal::assumed_role(std::move(a
->account
), match
[2]);
506 } else if (std::none_of(s
.begin(), s
.end(),
508 return (c
== ':') || (c
== '/');
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
));
518 "`{}` is not a supported AWS or Federated ARN. Supported ARNs are "
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
);
529 *errmsg
= fmt::format("RGW does not support principals of type `{}`.",
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());
542 if (w
->id
== TokenID::Version
) {
543 if (k
&& k
->kind
== TokenKind::version_key
) {
544 p
.version
= static_cast<Version
>(k
->specific
);
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
}));
553 } else if (w
->id
== TokenID::Id
) {
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
);
564 annotate(fmt::format("`{}` is not a valid effect.",
565 std::string_view
{s
, l
}));
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
)) {
576 is_validaction
= true;
577 (w
->id
== TokenID::Action
?
578 t
->action
= allValue
: t
->notaction
= allValue
);
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);
585 if ((t
->action
& s3AllValue
) == s3AllValue
) {
586 t
->action
[s3All
] = 1;
588 if ((t
->notaction
& s3AllValue
) == s3AllValue
) {
589 t
->notaction
[s3All
] = 1;
591 if ((t
->action
& iamAllValue
) == iamAllValue
) {
592 t
->action
[iamAll
] = 1;
594 if ((t
->notaction
& iamAllValue
) == iamAllValue
) {
595 t
->notaction
[iamAll
] = 1;
597 if ((t
->action
& stsAllValue
) == stsAllValue
) {
598 t
->action
[stsAll
] = 1;
600 if ((t
->notaction
& stsAllValue
) == stsAllValue
) {
601 t
->notaction
[stsAll
] = 1;
605 } else if (w
->id
== TokenID::Resource
|| w
->id
== TokenID::NotResource
) {
606 auto a
= ARN::parse({s
, l
}, true);
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
}));
615 // You can't specify resources for someone ELSE'S account.
616 if (a
->account
.empty() || a
->account
== pp
->tenant
||
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
));
623 annotate(fmt::format("Policy owned by tenant `{}` cannot grant access to "
624 "resource owned by tenant `{}`.",
625 pp
->tenant
, a
->account
));
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;
635 annotate(fmt::format("Invalid interpolation `{}`.",
636 std::string_view
{s
, l
}));
640 annotate(fmt::format("Invalid interpolation `{}`.",
641 std::string_view
{s
, l
}));
645 t
.conditions
.back().vals
.emplace_back(s
, l
);
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."));
654 auto& pri
= pp
->s
[pp
->s
.size() - 2].w
->id
== TokenID::Principal
?
655 t
->princ
: t
->noprinc
;
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
));
664 ldout(cct
, 0) << "Ignored principle `" << std::string_view
{s
, l
} << "`: "
669 annotate(fmt::format("`{}` is not valid in the context of `{}`.",
670 std::string_view
{s
, l
}, w
->name
));
678 if (is_action
&& !is_validaction
) {
679 annotate(fmt::format("`{}` is not a valid action.",
680 std::string_view
{s
, l
}));
687 bool ParseState::number(const char* s
, size_t l
) {
689 if (w
->kind
== TokenKind::cond_key
) {
690 auto& t
= pp
->policy
.statements
.back();
691 t
.conditions
.back().vals
.emplace_back(s
, l
);
694 annotate("Numbers are not allowed outside condition arguments.");
705 void ParseState::reset() {
709 bool ParseState::obj_start() {
710 if (w
->objectable
&& !objecting
) {
712 if (w
->id
== TokenID::Statement
) {
713 pp
->policy
.statements
.emplace_back();
719 annotate(fmt::format("The {} keyword cannot introduce an object.",
726 bool ParseState::array_end() {
727 if (arraying
&& !objecting
) {
732 annotate("Attempt to close unopened array.");
736 ostream
& operator <<(ostream
& m
, const MaskedIP
& ip
) {
737 // I have a theory about why std::bitset is the way it is.
739 for (int i
= 7; i
>= 0; --i
) {
741 for (int j
= 15; j
>= 0; --j
) {
742 hextet
|= (ip
.addr
[(i
* 16) + j
] << j
);
744 m
<< hex
<< (unsigned int) hextet
;
750 // It involves Satan.
751 for (int i
= 3; i
>= 0; --i
) {
753 for (int j
= 7; j
>= 0; --j
) {
754 b
|= (ip
.addr
[(i
* 8) + j
] << j
);
756 m
<< (unsigned int) b
;
762 m
<< "/" << dec
<< ip
.prefix
;
763 // It would explain a lot
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;
774 if (i
== env
.end()) {
775 if (op
== TokenID::ForAllValuesStringEquals
||
776 op
== TokenID::ForAllValuesStringEqualsIgnoreCase
||
777 op
== TokenID::ForAllValuesStringLike
) {
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
);
793 const auto& s
= i
->second
;
795 const auto& itr
= env
.equal_range(key
);
799 case TokenID::ForAnyValueStringEquals
:
800 case TokenID::StringEquals
:
801 return orrible(std::equal_to
<std::string
>(), itr
, isruntime
? runtime_vals
: vals
);
803 case TokenID::StringNotEquals
:
804 return orrible(std::not_fn(std::equal_to
<std::string
>()),
805 itr
, isruntime
? runtime_vals
: vals
);
807 case TokenID::ForAnyValueStringEqualsIgnoreCase
:
808 case TokenID::StringEqualsIgnoreCase
:
809 return orrible(ci_equal_to(), itr
, isruntime
? runtime_vals
: vals
);
811 case TokenID::StringNotEqualsIgnoreCase
:
812 return orrible(std::not_fn(ci_equal_to()), itr
, isruntime
? runtime_vals
: vals
);
814 case TokenID::ForAnyValueStringLike
:
815 case TokenID::StringLike
:
816 return orrible(string_like(), itr
, isruntime
? runtime_vals
: vals
);
818 case TokenID::StringNotLike
:
819 return orrible(std::not_fn(string_like()), itr
, isruntime
? runtime_vals
: vals
);
821 case TokenID::ForAllValuesStringEquals
:
822 return andible(std::equal_to
<std::string
>(), itr
, isruntime
? runtime_vals
: vals
);
824 case TokenID::ForAllValuesStringLike
:
825 return andible(string_like(), itr
, isruntime
? runtime_vals
: vals
);
827 case TokenID::ForAllValuesStringEqualsIgnoreCase
:
828 return andible(ci_equal_to(), itr
, isruntime
? runtime_vals
: vals
);
831 case TokenID::NumericEquals
:
832 return shortible(std::equal_to
<double>(), as_number
, s
, vals
);
834 case TokenID::NumericNotEquals
:
835 return shortible(std::not_fn(std::equal_to
<double>()),
839 case TokenID::NumericLessThan
:
840 return shortible(std::less
<double>(), as_number
, s
, vals
);
843 case TokenID::NumericLessThanEquals
:
844 return shortible(std::less_equal
<double>(), as_number
, s
, vals
);
846 case TokenID::NumericGreaterThan
:
847 return shortible(std::greater
<double>(), as_number
, s
, vals
);
849 case TokenID::NumericGreaterThanEquals
:
850 return shortible(std::greater_equal
<double>(), as_number
, s
, vals
);
853 case TokenID::DateEquals
:
854 return shortible(std::equal_to
<ceph::real_time
>(), as_date
, s
, vals
);
856 case TokenID::DateNotEquals
:
857 return shortible(std::not_fn(std::equal_to
<ceph::real_time
>()),
860 case TokenID::DateLessThan
:
861 return shortible(std::less
<ceph::real_time
>(), as_date
, s
, vals
);
864 case TokenID::DateLessThanEquals
:
865 return shortible(std::less_equal
<ceph::real_time
>(), as_date
, s
, vals
);
867 case TokenID::DateGreaterThan
:
868 return shortible(std::greater
<ceph::real_time
>(), as_date
, s
, vals
);
870 case TokenID::DateGreaterThanEquals
:
871 return shortible(std::greater_equal
<ceph::real_time
>(), as_date
, s
,
876 return shortible(std::equal_to
<bool>(), as_bool
, s
, vals
);
879 case TokenID::BinaryEquals
:
880 return shortible(std::equal_to
<ceph::bufferlist
>(), as_binary
, s
,
884 case TokenID::IpAddress
:
885 return shortible(std::equal_to
<MaskedIP
>(), as_network
, s
, vals
);
887 case TokenID::NotIpAddress
:
889 auto xc
= as_network(s
);
894 for (const string
& d
: vals
) {
895 auto xd
= as_network(d
);
908 // Amazon Resource Names! (Does S3 need this?)
909 TokenID::ArnEquals
, TokenID::ArnNotEquals
, TokenID::ArnLike
,
918 boost::optional
<MaskedIP
> Condition::as_network(const string
& s
) {
924 m
.v6
= (s
.find(':') == string::npos
) ? false : true;
926 auto slash
= s
.find('/');
927 if (slash
== string::npos
) {
928 m
.prefix
= m
.v6
? 128 : 32;
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)) {
941 if (slash
!= string::npos
) {
942 t
.assign(s
, 0, slash
);
948 if (inet_pton(AF_INET6
, p
->c_str(), static_cast<void*>(&a
)) != 1) {
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;
970 if (inet_pton(AF_INET
, p
->c_str(), static_cast<void*>(&a
)) != 1) {
974 m
.addr
= ntohl(a
.s_addr
);
981 const char* condop_string(const TokenID t
) {
983 case TokenID::StringEquals
:
984 return "StringEquals";
986 case TokenID::StringNotEquals
:
987 return "StringNotEquals";
989 case TokenID::StringEqualsIgnoreCase
:
990 return "StringEqualsIgnoreCase";
992 case TokenID::StringNotEqualsIgnoreCase
:
993 return "StringNotEqualsIgnoreCase";
995 case TokenID::StringLike
:
998 case TokenID::StringNotLike
:
999 return "StringNotLike";
1002 case TokenID::NumericEquals
:
1003 return "NumericEquals";
1005 case TokenID::NumericNotEquals
:
1006 return "NumericNotEquals";
1008 case TokenID::NumericLessThan
:
1009 return "NumericLessThan";
1011 case TokenID::NumericLessThanEquals
:
1012 return "NumericLessThanEquals";
1014 case TokenID::NumericGreaterThan
:
1015 return "NumericGreaterThan";
1017 case TokenID::NumericGreaterThanEquals
:
1018 return "NumericGreaterThanEquals";
1020 case TokenID::DateEquals
:
1021 return "DateEquals";
1023 case TokenID::DateNotEquals
:
1024 return "DateNotEquals";
1026 case TokenID::DateLessThan
:
1027 return "DateLessThan";
1029 case TokenID::DateLessThanEquals
:
1030 return "DateLessThanEquals";
1032 case TokenID::DateGreaterThan
:
1033 return "DateGreaterThan";
1035 case TokenID::DateGreaterThanEquals
:
1036 return "DateGreaterThanEquals";
1041 case TokenID::BinaryEquals
:
1042 return "BinaryEquals";
1044 case TokenID::IpAddress
:
1045 return "case TokenID::IpAddress";
1047 case TokenID::NotIpAddress
:
1048 return "NotIpAddress";
1050 case TokenID::ArnEquals
:
1053 case TokenID::ArnNotEquals
:
1054 return "ArnNotEquals";
1056 case TokenID::ArnLike
:
1059 case TokenID::ArnNotLike
:
1060 return "ArnNotLike";
1066 return "InvalidConditionOperator";
1070 template<typename Iterator
>
1071 ostream
& print_array(ostream
& m
, Iterator begin
, Iterator end
) {
1076 std::copy(begin
, end
, std::experimental::make_ostream_joiner(m
, ", "));
1082 template<typename Iterator
>
1083 ostream
& print_dict(ostream
& m
, Iterator begin
, Iterator end
) {
1085 std::copy(begin
, end
, std::experimental::make_ostream_joiner(m
, ", "));
1092 ostream
& operator <<(ostream
& m
, const Condition
& c
) {
1093 m
<< condop_string(c
.op
);
1097 m
<< ": { " << c
.key
;
1098 print_array(m
, c
.vals
.cbegin(), c
.vals
.cend());
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 {
1106 if (eval_principal(e
, ida
, princ_type
) == Effect::Deny
) {
1107 return Effect::Pass
;
1110 if (res
&& resource
.empty() && notresource
.empty()) {
1111 return Effect::Pass
;
1113 if (!res
&& (!resource
.empty() || !notresource
.empty())) {
1114 return Effect::Pass
;
1116 if (!resource
.empty() && res
) {
1117 if (!std::any_of(resource
.begin(), resource
.end(),
1118 [&res
](const ARN
& pattern
) {
1119 return pattern
.match(*res
);
1121 return Effect::Pass
;
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
);
1128 return Effect::Pass
;
1132 if (!(action
[act
] == 1) || (notaction
[act
] == 1)) {
1133 return Effect::Pass
;
1136 if (std::all_of(conditions
.begin(),
1138 [&e
](const Condition
& c
) { return c
.eval(e
);})) {
1142 return Effect::Pass
;
1145 Effect
Statement::eval_principal(const Environment
& e
,
1146 boost::optional
<const rgw::auth::Identity
&> ida
, boost::optional
<PolicyPrincipal
&> princ_type
) const {
1148 *princ_type
= PolicyPrincipal::Other
;
1151 if (princ
.empty() && noprinc
.empty()) {
1152 return Effect::Deny
;
1154 if (ida
->get_identity_type() != TYPE_ROLE
&& !princ
.empty() && !ida
->is_identity(princ
)) {
1155 return Effect::Deny
;
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
;
1162 if (ida
->is_identity(id
)) {
1163 if (p
.is_assumed_role() || p
.is_user()) {
1164 if (princ_type
) *princ_type
= PolicyPrincipal::Session
;
1166 if (princ_type
) *princ_type
= PolicyPrincipal::Role
;
1168 princ_matched
= true;
1171 if (!princ_matched
) {
1172 return Effect::Deny
;
1174 } else if (!noprinc
.empty() && ida
->is_identity(noprinc
)) {
1175 return Effect::Deny
;
1178 return Effect::Allow
;
1181 Effect
Statement::eval_conditions(const Environment
& e
) const {
1182 if (std::all_of(conditions
.begin(),
1184 [&e
](const Condition
& c
) { return c
.eval(e
);})) {
1185 return Effect::Allow
;
1187 return Effect::Deny
;
1191 const char* action_bit_string(uint64_t action
) {
1194 return "s3:GetObject";
1196 case s3GetObjectVersion
:
1197 return "s3:GetObjectVersion";
1200 return "s3:PutObject";
1202 case s3GetObjectAcl
:
1203 return "s3:GetObjectAcl";
1205 case s3GetObjectVersionAcl
:
1206 return "s3:GetObjectVersionAcl";
1208 case s3PutObjectAcl
:
1209 return "s3:PutObjectAcl";
1211 case s3PutObjectVersionAcl
:
1212 return "s3:PutObjectVersionAcl";
1214 case s3DeleteObject
:
1215 return "s3:DeleteObject";
1217 case s3DeleteObjectVersion
:
1218 return "s3:DeleteObjectVersion";
1220 case s3ListMultipartUploadParts
:
1221 return "s3:ListMultipartUploadParts";
1223 case s3AbortMultipartUpload
:
1224 return "s3:AbortMultipartUpload";
1226 case s3GetObjectTorrent
:
1227 return "s3:GetObjectTorrent";
1229 case s3GetObjectVersionTorrent
:
1230 return "s3:GetObjectVersionTorrent";
1232 case s3RestoreObject
:
1233 return "s3:RestoreObject";
1235 case s3CreateBucket
:
1236 return "s3:CreateBucket";
1238 case s3DeleteBucket
:
1239 return "s3:DeleteBucket";
1242 return "s3:ListBucket";
1244 case s3ListBucketVersions
:
1245 return "s3:ListBucketVersions";
1246 case s3ListAllMyBuckets
:
1247 return "s3:ListAllMyBuckets";
1249 case s3ListBucketMultipartUploads
:
1250 return "s3:ListBucketMultipartUploads";
1252 case s3GetAccelerateConfiguration
:
1253 return "s3:GetAccelerateConfiguration";
1255 case s3PutAccelerateConfiguration
:
1256 return "s3:PutAccelerateConfiguration";
1258 case s3GetBucketAcl
:
1259 return "s3:GetBucketAcl";
1261 case s3PutBucketAcl
:
1262 return "s3:PutBucketAcl";
1264 case s3GetBucketCORS
:
1265 return "s3:GetBucketCORS";
1267 case s3PutBucketCORS
:
1268 return "s3:PutBucketCORS";
1270 case s3GetBucketEncryption
:
1271 return "s3:GetBucketEncryption";
1273 case s3PutBucketEncryption
:
1274 return "s3:PutBucketEncryption";
1276 case s3GetBucketVersioning
:
1277 return "s3:GetBucketVersioning";
1279 case s3PutBucketVersioning
:
1280 return "s3:PutBucketVersioning";
1282 case s3GetBucketRequestPayment
:
1283 return "s3:GetBucketRequestPayment";
1285 case s3PutBucketRequestPayment
:
1286 return "s3:PutBucketRequestPayment";
1288 case s3GetBucketLocation
:
1289 return "s3:GetBucketLocation";
1291 case s3GetBucketPolicy
:
1292 return "s3:GetBucketPolicy";
1294 case s3DeleteBucketPolicy
:
1295 return "s3:DeleteBucketPolicy";
1297 case s3PutBucketPolicy
:
1298 return "s3:PutBucketPolicy";
1300 case s3GetBucketNotification
:
1301 return "s3:GetBucketNotification";
1303 case s3PutBucketNotification
:
1304 return "s3:PutBucketNotification";
1306 case s3GetBucketLogging
:
1307 return "s3:GetBucketLogging";
1309 case s3PutBucketLogging
:
1310 return "s3:PutBucketLogging";
1312 case s3GetBucketTagging
:
1313 return "s3:GetBucketTagging";
1315 case s3PutBucketTagging
:
1316 return "s3:PutBucketTagging";
1318 case s3GetBucketWebsite
:
1319 return "s3:GetBucketWebsite";
1321 case s3PutBucketWebsite
:
1322 return "s3:PutBucketWebsite";
1324 case s3DeleteBucketWebsite
:
1325 return "s3:DeleteBucketWebsite";
1327 case s3GetLifecycleConfiguration
:
1328 return "s3:GetLifecycleConfiguration";
1330 case s3PutLifecycleConfiguration
:
1331 return "s3:PutLifecycleConfiguration";
1333 case s3PutReplicationConfiguration
:
1334 return "s3:PutReplicationConfiguration";
1336 case s3GetReplicationConfiguration
:
1337 return "s3:GetReplicationConfiguration";
1339 case s3DeleteReplicationConfiguration
:
1340 return "s3:DeleteReplicationConfiguration";
1342 case s3PutObjectTagging
:
1343 return "s3:PutObjectTagging";
1345 case s3PutObjectVersionTagging
:
1346 return "s3:PutObjectVersionTagging";
1348 case s3GetObjectTagging
:
1349 return "s3:GetObjectTagging";
1351 case s3GetObjectVersionTagging
:
1352 return "s3:GetObjectVersionTagging";
1354 case s3DeleteObjectTagging
:
1355 return "s3:DeleteObjectTagging";
1357 case s3DeleteObjectVersionTagging
:
1358 return "s3:DeleteObjectVersionTagging";
1360 case s3PutBucketObjectLockConfiguration
:
1361 return "s3:PutBucketObjectLockConfiguration";
1363 case s3GetBucketObjectLockConfiguration
:
1364 return "s3:GetBucketObjectLockConfiguration";
1366 case s3PutObjectRetention
:
1367 return "s3:PutObjectRetention";
1369 case s3GetObjectRetention
:
1370 return "s3:GetObjectRetention";
1372 case s3PutObjectLegalHold
:
1373 return "s3:PutObjectLegalHold";
1375 case s3GetObjectLegalHold
:
1376 return "s3:GetObjectLegalHold";
1378 case s3BypassGovernanceRetention
:
1379 return "s3:BypassGovernanceRetention";
1381 case iamPutUserPolicy
:
1382 return "iam:PutUserPolicy";
1384 case iamGetUserPolicy
:
1385 return "iam:GetUserPolicy";
1387 case iamListUserPolicies
:
1388 return "iam:ListUserPolicies";
1390 case iamDeleteUserPolicy
:
1391 return "iam:DeleteUserPolicy";
1394 return "iam:CreateRole";
1397 return "iam:DeleteRole";
1400 return "iam:GetRole";
1402 case iamModifyRoleTrustPolicy
:
1403 return "iam:ModifyRoleTrustPolicy";
1406 return "iam:ListRoles";
1408 case iamPutRolePolicy
:
1409 return "iam:PutRolePolicy";
1411 case iamGetRolePolicy
:
1412 return "iam:GetRolePolicy";
1414 case iamListRolePolicies
:
1415 return "iam:ListRolePolicies";
1417 case iamDeleteRolePolicy
:
1418 return "iam:DeleteRolePolicy";
1420 case iamCreateOIDCProvider
:
1421 return "iam:CreateOIDCProvider";
1423 case iamDeleteOIDCProvider
:
1424 return "iam:DeleteOIDCProvider";
1426 case iamGetOIDCProvider
:
1427 return "iam:GetOIDCProvider";
1429 case iamListOIDCProviders
:
1430 return "iam:ListOIDCProviders";
1433 return "iam:TagRole";
1435 case iamListRoleTags
:
1436 return "iam:ListRoleTags";
1439 return "iam:UntagRole";
1442 return "iam:UpdateRole";
1445 return "sts:AssumeRole";
1447 case stsAssumeRoleWithWebIdentity
:
1448 return "sts:AssumeRoleWithWebIdentity";
1450 case stsGetSessionToken
:
1451 return "sts:GetSessionToken";
1454 return "sts:TagSession";
1459 ostream
& print_actions(ostream
& m
, const Action_t a
) {
1462 for (auto i
= 0U; i
< allCount
; ++i
) {
1469 m
<< action_bit_string(i
);
1481 ostream
& operator <<(ostream
& m
, const Statement
& s
) {
1484 m
<< "Sid: " << *s
.sid
<< ", ";
1486 if (!s
.princ
.empty()) {
1488 print_dict(m
, s
.princ
.cbegin(), s
.princ
.cend());
1491 if (!s
.noprinc
.empty()) {
1492 m
<< "NotPrincipal: ";
1493 print_dict(m
, s
.noprinc
.cbegin(), s
.noprinc
.cend());
1498 (s
.effect
== Effect::Allow
?
1499 (const char*) "Allow" :
1500 (const char*) "Deny");
1502 if (s
.action
.any() || s
.notaction
.any() || !s
.resource
.empty() ||
1503 !s
.notresource
.empty() || !s
.conditions
.empty()) {
1507 if (s
.action
.any()) {
1509 print_actions(m
, s
.action
);
1511 if (s
.notaction
.any() || !s
.resource
.empty() ||
1512 !s
.notresource
.empty() || !s
.conditions
.empty()) {
1517 if (s
.notaction
.any()) {
1519 print_actions(m
, s
.notaction
);
1521 if (!s
.resource
.empty() || !s
.notresource
.empty() ||
1522 !s
.conditions
.empty()) {
1527 if (!s
.resource
.empty()) {
1529 print_array(m
, s
.resource
.cbegin(), s
.resource
.cend());
1531 if (!s
.notresource
.empty() || !s
.conditions
.empty()) {
1536 if (!s
.notresource
.empty()) {
1537 m
<< "NotResource: ";
1538 print_array(m
, s
.notresource
.cbegin(), s
.notresource
.cend());
1540 if (!s
.conditions
.empty()) {
1545 if (!s
.conditions
.empty()) {
1547 print_dict(m
, s
.conditions
.cbegin(), s
.conditions
.cend());
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
);
1562 throw PolicyParseException(pr
, pp
.annotation
);
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
) {
1575 } else if (g
== Effect::Allow
) {
1579 return allowed
? Effect::Allow
: Effect::Pass
;
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
) {
1589 } else if (g
== Effect::Allow
) {
1593 return allowed
? Effect::Allow
: Effect::Deny
;
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
) {
1602 } else if (g
== Effect::Allow
) {
1606 return allowed
? Effect::Allow
: Effect::Deny
;
1609 ostream
& operator <<(ostream
& m
, const Policy
& p
) {
1611 << (p
.version
== Version::v2008_10_17
? "2008-10-17" : "2012-10-17");
1613 if (p
.id
|| !p
.statements
.empty()) {
1618 m
<< "Id: " << *p
.id
;
1619 if (!p
.statements
.empty()) {
1624 if (!p
.statements
.empty()) {
1625 m
<< "Statements: ";
1626 print_array(m
, p
.statements
.cbegin(), p
.statements
.cend());
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"}
1638 struct IsPublicStatement
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
;
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();
1657 bool is_public(const Policy
& p
)
1659 return std::any_of(p
.statements
.begin(), p
.statements
.end(), IsPublicStatement());