1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
12 #include <experimental/iterator>
14 #include "rapidjson/reader.h"
17 #include <arpa/inet.h>
18 #include "rgw_iam_policy.h"
21 constexpr int dout_subsys
= ceph_subsys_rgw
;
31 using std::stringstream
;
35 using std::unordered_map
;
37 using boost::container::flat_set
;
39 using std::regex_constants::ECMAScript
;
40 using std::regex_constants::optimize
;
41 using std::regex_match
;
44 using rapidjson::BaseReaderHandler
;
45 using rapidjson::UTF8
;
46 using rapidjson::SizeType
;
47 using rapidjson::Reader
;
48 using rapidjson::kParseCommentsFlag
;
49 using rapidjson::kParseNumbersAsStringsFlag
;
50 using rapidjson::StringStream
;
51 using rapidjson::ParseResult
;
53 using rgw::auth::Principal
;
57 #include "rgw_iam_policy_keywords.frag.cc"
65 boost::optional
<Partition
> to_partition(const smatch::value_type
& p
,
68 return Partition::aws
;
69 } else if (p
== "aws-cn") {
70 return Partition::aws_cn
;
71 } else if (p
== "aws-us-gov") {
72 return Partition::aws_us_gov
;
73 } else if (p
== "*" && wildcards
) {
74 return Partition::wildcard
;
82 boost::optional
<Service
> to_service(const smatch::value_type
& s
,
84 static const unordered_map
<string
, Service
> services
= {
85 { "acm", Service::acm
},
86 { "apigateway", Service::apigateway
},
87 { "appstream", Service::appstream
},
88 { "artifact", Service::artifact
},
89 { "autoscaling", Service::autoscaling
},
90 { "aws-marketplace", Service::aws_marketplace
},
91 { "aws-marketplace-management",
92 Service::aws_marketplace_management
},
93 { "aws-portal", Service::aws_portal
},
94 { "cloudformation", Service::cloudformation
},
95 { "cloudfront", Service::cloudfront
},
96 { "cloudhsm", Service::cloudhsm
},
97 { "cloudsearch", Service::cloudsearch
},
98 { "cloudtrail", Service::cloudtrail
},
99 { "cloudwatch", Service::cloudwatch
},
100 { "codebuild", Service::codebuild
},
101 { "codecommit", Service::codecommit
},
102 { "codedeploy", Service::codedeploy
},
103 { "codepipeline", Service::codepipeline
},
104 { "cognito-identity", Service::cognito_identity
},
105 { "cognito-idp", Service::cognito_idp
},
106 { "cognito-sync", Service::cognito_sync
},
107 { "config", Service::config
},
108 { "datapipeline", Service::datapipeline
},
109 { "devicefarm", Service::devicefarm
},
110 { "directconnect", Service::directconnect
},
111 { "dms", Service::dms
},
112 { "ds", Service::ds
},
113 { "dynamodb", Service::dynamodb
},
114 { "ec2", Service::ec2
},
115 { "ecr", Service::ecr
},
116 { "ecs", Service::ecs
},
117 { "elasticache", Service::elasticache
},
118 { "elasticbeanstalk", Service::elasticbeanstalk
},
119 { "elasticfilesystem", Service::elasticfilesystem
},
120 { "elasticloadbalancing", Service::elasticloadbalancing
},
121 { "elasticmapreduce", Service::elasticmapreduce
},
122 { "elastictranscoder", Service::elastictranscoder
},
123 { "es", Service::es
},
124 { "events", Service::events
},
125 { "firehose", Service::firehose
},
126 { "gamelift", Service::gamelift
},
127 { "glacier", Service::glacier
},
128 { "health", Service::health
},
129 { "iam", Service::iam
},
130 { "importexport", Service::importexport
},
131 { "inspector", Service::inspector
},
132 { "iot", Service::iot
},
133 { "kinesis", Service::kinesis
},
134 { "kinesisanalytics", Service::kinesisanalytics
},
135 { "kms", Service::kms
},
136 { "lambda", Service::lambda
},
137 { "lightsail", Service::lightsail
},
138 { "logs", Service::logs
},
139 { "machinelearning", Service::machinelearning
},
140 { "mobileanalytics", Service::mobileanalytics
},
141 { "mobilehub", Service::mobilehub
},
142 { "opsworks", Service::opsworks
},
143 { "opsworks-cm", Service::opsworks_cm
},
144 { "polly", Service::polly
},
145 { "rds", Service::rds
},
146 { "redshift", Service::redshift
},
147 { "route53", Service::route53
},
148 { "route53domains", Service::route53domains
},
149 { "s3", Service::s3
},
150 { "sdb", Service::sdb
},
151 { "servicecatalog", Service::servicecatalog
},
152 { "ses", Service::ses
},
153 { "sns", Service::sns
},
154 { "sqs", Service::sqs
},
155 { "ssm", Service::ssm
},
156 { "states", Service::states
},
157 { "storagegateway", Service::storagegateway
},
158 { "sts", Service::sts
},
159 { "support", Service::support
},
160 { "swf", Service::swf
},
161 { "trustedadvisor", Service::trustedadvisor
},
162 { "waf", Service::waf
},
163 { "workmail", Service::workmail
},
164 { "workspaces", Service::workspaces
}};
166 if (wildcards
&& s
== "*") {
167 return Service::wildcard
;
170 auto i
= services
.find(s
);
171 if (i
== services
.end()) {
179 ARN::ARN(const rgw_obj
& o
)
180 : partition(Partition::aws
),
181 service(Service::s3
),
183 account(o
.bucket
.tenant
),
184 resource(o
.bucket
.name
)
186 resource
.push_back('/');
187 resource
.append(o
.key
.name
);
190 ARN::ARN(const rgw_bucket
& b
)
191 : partition(Partition::aws
),
192 service(Service::s3
),
197 ARN::ARN(const rgw_bucket
& b
, const string
& o
)
198 : partition(Partition::aws
),
199 service(Service::s3
),
203 resource
.push_back('/');
207 ARN::ARN(const string
& resource_name
, const string
& type
, const string
& tenant
, bool has_path
)
208 : partition(Partition::aws
),
209 service(Service::iam
),
214 resource
.push_back('/');
215 resource
.append(resource_name
);
218 boost::optional
<ARN
> ARN::parse(const string
& s
, bool wildcards
) {
219 static const regex
rx_wild("arn:([^:]*):([^:]*):([^:]*):([^:]*):([^:]*)",
220 std::regex_constants::ECMAScript
|
221 std::regex_constants::optimize
);
222 static const regex
rx_no_wild(
223 "arn:([^:*]*):([^:*]*):([^:*]*):([^:*]*):(.*)",
224 std::regex_constants::ECMAScript
|
225 std::regex_constants::optimize
);
229 if ((s
== "*") && wildcards
) {
230 return ARN(Partition::wildcard
, Service::wildcard
, "*", "*", "*");
231 } else if (regex_match(s
, match
, wildcards
? rx_wild
: rx_no_wild
) &&
233 if (auto p
= to_partition(match
[1], wildcards
)) {
234 if (auto s
= to_service(match
[2], wildcards
)) {
235 return ARN(*p
, *s
, match
[3], match
[4], match
[5]);
242 string
ARN::to_string() const {
245 if (partition
== Partition::aws
) {
247 } else if (partition
== Partition::aws_cn
) {
249 } else if (partition
== Partition::aws_us_gov
) {
250 s
.append("aws-us-gov:");
255 static const unordered_map
<Service
, string
> services
= {
256 { Service::acm
, "acm" },
257 { Service::apigateway
, "apigateway" },
258 { Service::appstream
, "appstream" },
259 { Service::artifact
, "artifact" },
260 { Service::autoscaling
, "autoscaling" },
261 { Service::aws_marketplace
, "aws-marketplace" },
262 { Service::aws_marketplace_management
, "aws-marketplace-management" },
263 { Service::aws_portal
, "aws-portal" },
264 { Service::cloudformation
, "cloudformation" },
265 { Service::cloudfront
, "cloudfront" },
266 { Service::cloudhsm
, "cloudhsm" },
267 { Service::cloudsearch
, "cloudsearch" },
268 { Service::cloudtrail
, "cloudtrail" },
269 { Service::cloudwatch
, "cloudwatch" },
270 { Service::codebuild
, "codebuild" },
271 { Service::codecommit
, "codecommit" },
272 { Service::codedeploy
, "codedeploy" },
273 { Service::codepipeline
, "codepipeline" },
274 { Service::cognito_identity
, "cognito-identity" },
275 { Service::cognito_idp
, "cognito-idp" },
276 { Service::cognito_sync
, "cognito-sync" },
277 { Service::config
, "config" },
278 { Service::datapipeline
, "datapipeline" },
279 { Service::devicefarm
, "devicefarm" },
280 { Service::directconnect
, "directconnect" },
281 { Service::dms
, "dms" },
282 { Service::ds
, "ds" },
283 { Service::dynamodb
, "dynamodb" },
284 { Service::ec2
, "ec2" },
285 { Service::ecr
, "ecr" },
286 { Service::ecs
, "ecs" },
287 { Service::elasticache
, "elasticache" },
288 { Service::elasticbeanstalk
, "elasticbeanstalk" },
289 { Service::elasticfilesystem
, "elasticfilesystem" },
290 { Service::elasticloadbalancing
, "elasticloadbalancing" },
291 { Service::elasticmapreduce
, "elasticmapreduce" },
292 { Service::elastictranscoder
, "elastictranscoder" },
293 { Service::es
, "es" },
294 { Service::events
, "events" },
295 { Service::firehose
, "firehose" },
296 { Service::gamelift
, "gamelift" },
297 { Service::glacier
, "glacier" },
298 { Service::health
, "health" },
299 { Service::iam
, "iam" },
300 { Service::importexport
, "importexport" },
301 { Service::inspector
, "inspector" },
302 { Service::iot
, "iot" },
303 { Service::kinesis
, "kinesis" },
304 { Service::kinesisanalytics
, "kinesisanalytics" },
305 { Service::kms
, "kms" },
306 { Service::lambda
, "lambda" },
307 { Service::lightsail
, "lightsail" },
308 { Service::logs
, "logs" },
309 { Service::machinelearning
, "machinelearning" },
310 { Service::mobileanalytics
, "mobileanalytics" },
311 { Service::mobilehub
, "mobilehub" },
312 { Service::opsworks
, "opsworks" },
313 { Service::opsworks_cm
, "opsworks-cm" },
314 { Service::polly
, "polly" },
315 { Service::rds
, "rds" },
316 { Service::redshift
, "redshift" },
317 { Service::route53
, "route53" },
318 { Service::route53domains
, "route53domains" },
319 { Service::s3
, "s3" },
320 { Service::sdb
, "sdb" },
321 { Service::servicecatalog
, "servicecatalog" },
322 { Service::ses
, "ses" },
323 { Service::sns
, "sns" },
324 { Service::sqs
, "sqs" },
325 { Service::ssm
, "ssm" },
326 { Service::states
, "states" },
327 { Service::storagegateway
, "storagegateway" },
328 { Service::sts
, "sts" },
329 { Service::support
, "support" },
330 { Service::swf
, "swf" },
331 { Service::trustedadvisor
, "trustedadvisor" },
332 { Service::waf
, "waf" },
333 { Service::workmail
, "workmail" },
334 { Service::workspaces
, "workspaces" }};
336 auto i
= services
.find(service
);
337 if (i
!= services
.end()) {
355 bool operator ==(const ARN
& l
, const ARN
& r
) {
356 return ((l
.partition
== r
.partition
) &&
357 (l
.service
== r
.service
) &&
358 (l
.region
== r
.region
) &&
359 (l
.account
== r
.account
) &&
360 (l
.resource
== r
.resource
));
362 bool operator <(const ARN
& l
, const ARN
& r
) {
363 return ((l
.partition
< r
.partition
) ||
364 (l
.service
< r
.service
) ||
365 (l
.region
< r
.region
) ||
366 (l
.account
< r
.account
) ||
367 (l
.resource
< r
.resource
));
370 // The candidate is not allowed to have wildcards. The only way to
371 // do that sanely would be to use unification rather than matching.
372 bool ARN::match(const ARN
& candidate
) const {
373 if ((candidate
.partition
== Partition::wildcard
) ||
374 (partition
!= candidate
.partition
&& partition
375 != Partition::wildcard
)) {
379 if ((candidate
.service
== Service::wildcard
) ||
380 (service
!= candidate
.service
&& service
!= Service::wildcard
)) {
384 if (!match_policy(region
, candidate
.region
, MATCH_POLICY_ARN
)) {
388 if (!match_policy(account
, candidate
.account
, MATCH_POLICY_ARN
)) {
392 if (!match_policy(resource
, candidate
.resource
, MATCH_POLICY_RESOURCE
)) {
399 static const actpair actpairs
[] =
400 {{ "s3:AbortMultipartUpload", s3AbortMultipartUpload
},
401 { "s3:CreateBucket", s3CreateBucket
},
402 { "s3:DeleteBucketPolicy", s3DeleteBucketPolicy
},
403 { "s3:DeleteBucket", s3DeleteBucket
},
404 { "s3:DeleteBucketWebsite", s3DeleteBucketWebsite
},
405 { "s3:DeleteObject", s3DeleteObject
},
406 { "s3:DeleteObjectVersion", s3DeleteObjectVersion
},
407 { "s3:DeleteObjectTagging", s3DeleteObjectTagging
},
408 { "s3:DeleteObjectVersionTagging", s3DeleteObjectVersionTagging
},
409 { "s3:DeleteReplicationConfiguration", s3DeleteReplicationConfiguration
},
410 { "s3:GetAccelerateConfiguration", s3GetAccelerateConfiguration
},
411 { "s3:GetBucketAcl", s3GetBucketAcl
},
412 { "s3:GetBucketCORS", s3GetBucketCORS
},
413 { "s3:GetBucketLocation", s3GetBucketLocation
},
414 { "s3:GetBucketLogging", s3GetBucketLogging
},
415 { "s3:GetBucketNotification", s3GetBucketNotification
},
416 { "s3:GetBucketPolicy", s3GetBucketPolicy
},
417 { "s3:GetBucketRequestPayment", s3GetBucketRequestPayment
},
418 { "s3:GetBucketTagging", s3GetBucketTagging
},
419 { "s3:GetBucketVersioning", s3GetBucketVersioning
},
420 { "s3:GetBucketWebsite", s3GetBucketWebsite
},
421 { "s3:GetLifecycleConfiguration", s3GetLifecycleConfiguration
},
422 { "s3:GetObjectAcl", s3GetObjectAcl
},
423 { "s3:GetObject", s3GetObject
},
424 { "s3:GetObjectTorrent", s3GetObjectTorrent
},
425 { "s3:GetObjectVersionAcl", s3GetObjectVersionAcl
},
426 { "s3:GetObjectVersion", s3GetObjectVersion
},
427 { "s3:GetObjectVersionTorrent", s3GetObjectVersionTorrent
},
428 { "s3:GetObjectTagging", s3GetObjectTagging
},
429 { "s3:GetObjectVersionTagging", s3GetObjectVersionTagging
},
430 { "s3:GetReplicationConfiguration", s3GetReplicationConfiguration
},
431 { "s3:ListAllMyBuckets", s3ListAllMyBuckets
},
432 { "s3:ListBucketMultipartUploads", s3ListBucketMultipartUploads
},
433 { "s3:ListBucket", s3ListBucket
},
434 { "s3:ListBucketVersions", s3ListBucketVersions
},
435 { "s3:ListMultipartUploadParts", s3ListMultipartUploadParts
},
436 { "s3:PutAccelerateConfiguration", s3PutAccelerateConfiguration
},
437 { "s3:PutBucketAcl", s3PutBucketAcl
},
438 { "s3:PutBucketCORS", s3PutBucketCORS
},
439 { "s3:PutBucketLogging", s3PutBucketLogging
},
440 { "s3:PutBucketNotification", s3PutBucketNotification
},
441 { "s3:PutBucketPolicy", s3PutBucketPolicy
},
442 { "s3:PutBucketRequestPayment", s3PutBucketRequestPayment
},
443 { "s3:PutBucketTagging", s3PutBucketTagging
},
444 { "s3:PutBucketVersioning", s3PutBucketVersioning
},
445 { "s3:PutBucketWebsite", s3PutBucketWebsite
},
446 { "s3:PutLifecycleConfiguration", s3PutLifecycleConfiguration
},
447 { "s3:PutObjectAcl", s3PutObjectAcl
},
448 { "s3:PutObject", s3PutObject
},
449 { "s3:PutObjectVersionAcl", s3PutObjectVersionAcl
},
450 { "s3:PutObjectTagging", s3PutObjectTagging
},
451 { "s3:PutObjectVersionTagging", s3PutObjectVersionTagging
},
452 { "s3:PutReplicationConfiguration", s3PutReplicationConfiguration
},
453 { "s3:RestoreObject", s3RestoreObject
},
454 { "iam:PutUserPolicy", iamPutUserPolicy
},
455 { "iam:GetUserPolicy", iamGetUserPolicy
},
456 { "iam:DeleteUserPolicy", iamDeleteUserPolicy
},
457 { "iam:ListUserPolicies", iamListUserPolicies
},
458 { "iam:CreateRole", iamCreateRole
},
459 { "iam:DeleteRole", iamDeleteRole
},
460 { "iam:GetRole", iamGetRole
},
461 { "iam:ModifyRole", iamModifyRole
},
462 { "iam:ListRoles", iamListRoles
},
463 { "iam:PutRolePolicy", iamPutRolePolicy
},
464 { "iam:GetRolePolicy", iamGetRolePolicy
},
465 { "iam:ListRolePolicies", iamListRolePolicies
},
466 { "iam:DeleteRolePolicy", iamDeleteRolePolicy
},
467 { "sts:AssumeRole", stsAssumeRole
},
468 { "sts:AssumeRoleWithWebIdentity", stsAssumeRoleWithWebIdentity
},
469 { "sts:GetSessionToken", stsGetSessionToken
},
474 const Keyword top
[1]{"<Top>", TokenKind::pseudo
, TokenID::Top
, 0, false,
476 const Keyword cond_key
[1]{"<Condition Key>", TokenKind::cond_key
,
477 TokenID::CondKey
, 0, true, false};
483 bool arraying
= false;
484 bool objecting
= false;
485 bool cond_ifexists
= false;
489 ParseState(PolicyParser
* pp
, const Keyword
* w
)
497 if (w
->arrayable
&& !arraying
) {
506 bool key(const char* s
, size_t l
);
507 bool do_string(CephContext
* cct
, const char* s
, size_t l
);
508 bool number(const char* str
, size_t l
);
511 // If this confuses you, look up the Curiously Recurring Template Pattern
512 struct PolicyParser
: public BaseReaderHandler
<UTF8
<>, PolicyParser
> {
514 std::vector
<ParseState
> s
;
516 const string
& tenant
;
522 uint32_t dex(TokenID in
) const {
524 case TokenID::Version
:
528 case TokenID::Statement
:
532 case TokenID::Effect
:
534 case TokenID::Principal
:
536 case TokenID::NotPrincipal
:
538 case TokenID::Action
:
540 case TokenID::NotAction
:
542 case TokenID::Resource
:
544 case TokenID::NotResource
:
546 case TokenID::Condition
:
550 case TokenID::Federated
:
552 case TokenID::Service
:
554 case TokenID::CanonicalUser
:
560 bool test(TokenID in
) {
561 return seen
& dex(in
);
563 void set(TokenID in
) {
565 if (dex(in
) & (dex(TokenID::Sid
) | dex(TokenID::Effect
) |
566 dex(TokenID::Principal
) | dex(TokenID::NotPrincipal
) |
567 dex(TokenID::Action
) | dex(TokenID::NotAction
) |
568 dex(TokenID::Resource
) | dex(TokenID::NotResource
) |
569 dex(TokenID::Condition
) | dex(TokenID::AWS
) |
570 dex(TokenID::Federated
) | dex(TokenID::Service
) |
571 dex(TokenID::CanonicalUser
))) {
575 void set(std::initializer_list
<TokenID
> l
) {
578 if (dex(in
) & (dex(TokenID::Sid
) | dex(TokenID::Effect
) |
579 dex(TokenID::Principal
) | dex(TokenID::NotPrincipal
) |
580 dex(TokenID::Action
) | dex(TokenID::NotAction
) |
581 dex(TokenID::Resource
) | dex(TokenID::NotResource
) |
582 dex(TokenID::Condition
) | dex(TokenID::AWS
) |
583 dex(TokenID::Federated
) | dex(TokenID::Service
) |
584 dex(TokenID::CanonicalUser
))) {
589 void reset(TokenID in
) {
591 if (dex(in
) & (dex(TokenID::Sid
) | dex(TokenID::Effect
) |
592 dex(TokenID::Principal
) | dex(TokenID::NotPrincipal
) |
593 dex(TokenID::Action
) | dex(TokenID::NotAction
) |
594 dex(TokenID::Resource
) | dex(TokenID::NotResource
) |
595 dex(TokenID::Condition
) | dex(TokenID::AWS
) |
596 dex(TokenID::Federated
) | dex(TokenID::Service
) |
597 dex(TokenID::CanonicalUser
))) {
601 void reset(std::initializer_list
<TokenID
> l
) {
604 if (dex(in
) & (dex(TokenID::Sid
) | dex(TokenID::Effect
) |
605 dex(TokenID::Principal
) | dex(TokenID::NotPrincipal
) |
606 dex(TokenID::Action
) | dex(TokenID::NotAction
) |
607 dex(TokenID::Resource
) | dex(TokenID::NotResource
) |
608 dex(TokenID::Condition
) | dex(TokenID::AWS
) |
609 dex(TokenID::Federated
) | dex(TokenID::Service
) |
610 dex(TokenID::CanonicalUser
))) {
615 void reset(uint32_t& v
) {
620 PolicyParser(CephContext
* cct
, const string
& tenant
, Policy
& policy
)
621 : cct(cct
), tenant(tenant
), policy(policy
) {}
622 PolicyParser(const PolicyParser
& policy
) = delete;
626 s
.push_back({this, top
});
627 s
.back().objecting
= true;
631 return s
.back().obj_start();
633 bool EndObject(SizeType memberCount
) {
637 return s
.back().obj_end();
639 bool Key(const char* str
, SizeType length
, bool copy
) {
643 return s
.back().key(str
, length
);
646 bool String(const char* str
, SizeType length
, bool copy
) {
650 return s
.back().do_string(cct
, str
, length
);
652 bool RawNumber(const char* str
, SizeType length
, bool copy
) {
657 return s
.back().number(str
, length
);
664 return s
.back().array_start();
666 bool EndArray(SizeType
) {
671 return s
.back().array_end();
680 // I really despise this misfeature of C++.
682 bool ParseState::obj_end() {
695 bool ParseState::key(const char* s
, size_t l
) {
697 bool ifexists
= false;
698 if (w
->id
== TokenID::Condition
&& w
->kind
== TokenKind::statement
) {
699 static constexpr char IfExists
[] = "IfExists";
700 if (boost::algorithm::ends_with(boost::string_view
{s
, l
}, IfExists
)) {
702 token_len
-= sizeof(IfExists
)-1;
705 auto k
= pp
->tokens
.lookup(s
, token_len
);
708 if (w
->kind
== TokenKind::cond_op
) {
710 auto& t
= pp
->policy
.statements
.back();
711 auto c_ife
= cond_ifexists
;
712 pp
->s
.emplace_back(pp
, cond_key
);
713 t
.conditions
.emplace_back(id
, s
, l
, c_ife
);
720 // If the token we're going with belongs within the condition at the
721 // top of the stack and we haven't already encountered it, push it
724 if ((((w
->id
== TokenID::Top
) && (k
->kind
== TokenKind::top
)) ||
726 ((w
->id
== TokenID::Statement
) && (k
->kind
== TokenKind::statement
)) ||
729 ((w
->id
== TokenID::Principal
|| w
->id
== TokenID::NotPrincipal
) &&
730 (k
->kind
== TokenKind::princ_type
))) &&
732 // Check that it hasn't been encountered. Note that this
733 // conjoins with the run of disjunctions above.
736 pp
->s
.emplace_back(pp
, k
);
738 } else if ((w
->id
== TokenID::Condition
) &&
739 (k
->kind
== TokenKind::cond_op
)) {
740 pp
->s
.emplace_back(pp
, k
);
741 pp
->s
.back().cond_ifexists
= ifexists
;
747 // I should just rewrite a few helper functions to use iterators,
748 // which will make all of this ever so much nicer.
749 static boost::optional
<Principal
> parse_principal(CephContext
* cct
, TokenID t
,
752 if ((t
== TokenID::AWS
) && (s
== "*")) {
753 return Principal::wildcard();
755 // Do nothing for now.
756 } else if (t
== TokenID::CanonicalUser
) {
758 } // AWS and Federated ARNs
759 else if (t
== TokenID::AWS
|| t
== TokenID::Federated
) {
760 if (auto a
= ARN::parse(s
)) {
761 if (a
->resource
== "root") {
762 return Principal::tenant(std::move(a
->account
));
765 static const char rx_str
[] = "([^/]*)/(.*)";
766 static const regex
rx(rx_str
, sizeof(rx_str
) - 1,
767 std::regex_constants::ECMAScript
|
768 std::regex_constants::optimize
);
770 if (regex_match(a
->resource
, match
, rx
) && match
.size() == 3) {
771 if (match
[1] == "user") {
772 return Principal::user(std::move(a
->account
),
776 if (match
[1] == "role") {
777 return Principal::role(std::move(a
->account
),
781 if (match
[1] == "oidc-provider") {
782 return Principal::oidc_provider(std::move(match
[2]));
786 if (std::none_of(s
.begin(), s
.end(),
788 return (c
== ':') || (c
== '/');
790 // Since tenants are simply prefixes, there's no really good
791 // way to see if one exists or not. So we return the thing and
792 // let them try to match against it.
793 return Principal::tenant(std::move(s
));
798 ldout(cct
, 0) << "Supplied principal is discarded: " << s
<< dendl
;
802 bool ParseState::do_string(CephContext
* cct
, const char* s
, size_t l
) {
803 auto k
= pp
->tokens
.lookup(s
, l
);
804 Policy
& p
= pp
->policy
;
805 bool is_action
= false;
806 bool is_validaction
= false;
807 Statement
* t
= p
.statements
.empty() ? nullptr : &(p
.statements
.back());
810 if ((w
->id
== TokenID::Version
) && k
&&
811 k
->kind
== TokenKind::version_key
) {
812 p
.version
= static_cast<Version
>(k
->specific
);
813 } else if (w
->id
== TokenID::Id
) {
818 } else if (w
->id
== TokenID::Sid
) {
819 t
->sid
.emplace(s
, l
);
820 } else if ((w
->id
== TokenID::Effect
) && k
&&
821 k
->kind
== TokenKind::effect_key
) {
822 t
->effect
= static_cast<Effect
>(k
->specific
);
823 } else if (w
->id
== TokenID::Principal
&& s
&& *s
== '*') {
824 t
->princ
.emplace(Principal::wildcard());
825 } else if (w
->id
== TokenID::NotPrincipal
&& s
&& *s
== '*') {
826 t
->noprinc
.emplace(Principal::wildcard());
827 } else if ((w
->id
== TokenID::Action
) ||
828 (w
->id
== TokenID::NotAction
)) {
831 is_validaction
= true;
832 (w
->id
== TokenID::Action
?
833 t
->action
= allValue
: t
->notaction
= allValue
);
835 for (auto& p
: actpairs
) {
836 if (match_policy({s
, l
}, p
.name
, MATCH_POLICY_ACTION
)) {
837 is_validaction
= true;
838 (w
->id
== TokenID::Action
? t
->action
[p
.bit
] = 1 : t
->notaction
[p
.bit
] = 1);
840 if ((t
->action
& s3AllValue
) == s3AllValue
) {
841 t
->action
[s3All
] = 1;
843 if ((t
->notaction
& s3AllValue
) == s3AllValue
) {
844 t
->notaction
[s3All
] = 1;
846 if ((t
->action
& iamAllValue
) == iamAllValue
) {
847 t
->action
[iamAll
] = 1;
849 if ((t
->notaction
& iamAllValue
) == iamAllValue
) {
850 t
->notaction
[iamAll
] = 1;
852 if ((t
->action
& stsAllValue
) == stsAllValue
) {
853 t
->action
[stsAll
] = 1;
855 if ((t
->notaction
& stsAllValue
) == stsAllValue
) {
856 t
->notaction
[stsAll
] = 1;
860 } else if (w
->id
== TokenID::Resource
|| w
->id
== TokenID::NotResource
) {
861 auto a
= ARN::parse({s
, l
}, true);
862 // You can't specify resources for someone ELSE'S account.
863 if (a
&& (a
->account
.empty() || a
->account
== pp
->tenant
||
864 a
->account
== "*")) {
865 if (a
->account
.empty() || a
->account
== "*")
866 a
->account
= pp
->tenant
;
867 (w
->id
== TokenID::Resource
? t
->resource
: t
->notresource
)
868 .emplace(std::move(*a
));
871 ldout(cct
, 0) << "Supplied resource is discarded: " << string(s
, l
)
873 } else if (w
->kind
== TokenKind::cond_key
) {
874 auto& t
= pp
->policy
.statements
.back();
875 t
.conditions
.back().vals
.emplace_back(s
, l
);
879 } else if (w
->kind
== TokenKind::princ_type
) {
880 if (pp
->s
.size() <= 1) {
883 auto& pri
= pp
->s
[pp
->s
.size() - 2].w
->id
== TokenID::Principal
?
884 t
->princ
: t
->noprinc
;
887 if (auto o
= parse_principal(pp
->cct
, w
->id
, string(s
, l
))) {
888 pri
.emplace(std::move(*o
));
901 if (is_action
&& !is_validaction
){
908 bool ParseState::number(const char* s
, size_t l
) {
910 if (w
->kind
== TokenKind::cond_key
) {
911 auto& t
= pp
->policy
.statements
.back();
912 t
.conditions
.back().vals
.emplace_back(s
, l
);
927 void ParseState::reset() {
931 bool ParseState::obj_start() {
932 if (w
->objectable
&& !objecting
) {
934 if (w
->id
== TokenID::Statement
) {
935 pp
->policy
.statements
.emplace_back();
945 bool ParseState::array_end() {
946 if (arraying
&& !objecting
) {
954 ostream
& operator <<(ostream
& m
, const MaskedIP
& ip
) {
955 // I have a theory about why std::bitset is the way it is.
957 for (int i
= 7; i
>= 0; --i
) {
959 for (int j
= 15; j
>= 0; --j
) {
960 hextet
|= (ip
.addr
[(i
* 16) + j
] << j
);
962 m
<< hex
<< (unsigned int) hextet
;
968 // It involves Satan.
969 for (int i
= 3; i
>= 0; --i
) {
971 for (int j
= 7; j
>= 0; --j
) {
972 b
|= (ip
.addr
[(i
* 8) + j
] << j
);
974 m
<< (unsigned int) b
;
980 m
<< "/" << dec
<< ip
.prefix
;
981 // It would explain a lot
985 bool Condition::eval(const Environment
& env
) const {
986 auto i
= env
.find(key
);
987 if (op
== TokenID::Null
) {
988 return i
== env
.end() ? true : false;
991 if (i
== env
.end()) {
994 const auto& s
= i
->second
;
998 case TokenID::StringEquals
:
999 return orrible(std::equal_to
<std::string
>(), s
, vals
);
1001 case TokenID::StringNotEquals
:
1002 return orrible(std::not_fn(std::equal_to
<std::string
>()),
1005 case TokenID::StringEqualsIgnoreCase
:
1006 return orrible(ci_equal_to(), s
, vals
);
1008 case TokenID::StringNotEqualsIgnoreCase
:
1009 return orrible(std::not_fn(ci_equal_to()), s
, vals
);
1011 case TokenID::StringLike
:
1012 return orrible(string_like(), s
, vals
);
1014 case TokenID::StringNotLike
:
1015 return orrible(std::not_fn(string_like()), s
, vals
);
1018 case TokenID::NumericEquals
:
1019 return shortible(std::equal_to
<double>(), as_number
, s
, vals
);
1021 case TokenID::NumericNotEquals
:
1022 return shortible(std::not_fn(std::equal_to
<double>()),
1023 as_number
, s
, vals
);
1026 case TokenID::NumericLessThan
:
1027 return shortible(std::less
<double>(), as_number
, s
, vals
);
1030 case TokenID::NumericLessThanEquals
:
1031 return shortible(std::less_equal
<double>(), as_number
, s
, vals
);
1033 case TokenID::NumericGreaterThan
:
1034 return shortible(std::greater
<double>(), as_number
, s
, vals
);
1036 case TokenID::NumericGreaterThanEquals
:
1037 return shortible(std::greater_equal
<double>(), as_number
, s
, vals
);
1040 case TokenID::DateEquals
:
1041 return shortible(std::equal_to
<ceph::real_time
>(), as_date
, s
, vals
);
1043 case TokenID::DateNotEquals
:
1044 return shortible(std::not_fn(std::equal_to
<ceph::real_time
>()),
1047 case TokenID::DateLessThan
:
1048 return shortible(std::less
<ceph::real_time
>(), as_date
, s
, vals
);
1051 case TokenID::DateLessThanEquals
:
1052 return shortible(std::less_equal
<ceph::real_time
>(), as_date
, s
, vals
);
1054 case TokenID::DateGreaterThan
:
1055 return shortible(std::greater
<ceph::real_time
>(), as_date
, s
, vals
);
1057 case TokenID::DateGreaterThanEquals
:
1058 return shortible(std::greater_equal
<ceph::real_time
>(), as_date
, s
,
1063 return shortible(std::equal_to
<bool>(), as_bool
, s
, vals
);
1066 case TokenID::BinaryEquals
:
1067 return shortible(std::equal_to
<ceph::bufferlist
>(), as_binary
, s
,
1071 case TokenID::IpAddress
:
1072 return shortible(std::equal_to
<MaskedIP
>(), as_network
, s
, vals
);
1074 case TokenID::NotIpAddress
:
1076 auto xc
= as_network(s
);
1081 for (const string
& d
: vals
) {
1082 auto xd
= as_network(d
);
1095 // Amazon Resource Names! (Does S3 need this?)
1096 TokenID::ArnEquals
, TokenID::ArnNotEquals
, TokenID::ArnLike
,
1097 TokenID::ArnNotLike
,
1105 boost::optional
<MaskedIP
> Condition::as_network(const string
& s
) {
1111 m
.v6
= (s
.find(':') == string::npos
) ? false : true;
1113 auto slash
= s
.find('/');
1114 if (slash
== string::npos
) {
1115 m
.prefix
= m
.v6
? 128 : 32;
1118 m
.prefix
= strtoul(s
.data() + slash
+ 1, &end
, 10);
1119 if (*end
!= 0 || (m
.v6
&& m
.prefix
> 128) ||
1120 (!m
.v6
&& m
.prefix
> 32)) {
1128 if (slash
!= string::npos
) {
1129 t
.assign(s
, 0, slash
);
1135 if (inet_pton(AF_INET6
, p
->c_str(), static_cast<void*>(&a
)) != 1) {
1139 m
.addr
|= Address(a
.s6_addr
[15]) << 0;
1140 m
.addr
|= Address(a
.s6_addr
[14]) << 8;
1141 m
.addr
|= Address(a
.s6_addr
[13]) << 16;
1142 m
.addr
|= Address(a
.s6_addr
[12]) << 24;
1143 m
.addr
|= Address(a
.s6_addr
[11]) << 32;
1144 m
.addr
|= Address(a
.s6_addr
[10]) << 40;
1145 m
.addr
|= Address(a
.s6_addr
[9]) << 48;
1146 m
.addr
|= Address(a
.s6_addr
[8]) << 56;
1147 m
.addr
|= Address(a
.s6_addr
[7]) << 64;
1148 m
.addr
|= Address(a
.s6_addr
[6]) << 72;
1149 m
.addr
|= Address(a
.s6_addr
[5]) << 80;
1150 m
.addr
|= Address(a
.s6_addr
[4]) << 88;
1151 m
.addr
|= Address(a
.s6_addr
[3]) << 96;
1152 m
.addr
|= Address(a
.s6_addr
[2]) << 104;
1153 m
.addr
|= Address(a
.s6_addr
[1]) << 112;
1154 m
.addr
|= Address(a
.s6_addr
[0]) << 120;
1157 if (inet_pton(AF_INET
, p
->c_str(), static_cast<void*>(&a
)) != 1) {
1161 m
.addr
= ntohl(a
.s_addr
);
1168 const char* condop_string(const TokenID t
) {
1170 case TokenID::StringEquals
:
1171 return "StringEquals";
1173 case TokenID::StringNotEquals
:
1174 return "StringNotEquals";
1176 case TokenID::StringEqualsIgnoreCase
:
1177 return "StringEqualsIgnoreCase";
1179 case TokenID::StringNotEqualsIgnoreCase
:
1180 return "StringNotEqualsIgnoreCase";
1182 case TokenID::StringLike
:
1183 return "StringLike";
1185 case TokenID::StringNotLike
:
1186 return "StringNotLike";
1189 case TokenID::NumericEquals
:
1190 return "NumericEquals";
1192 case TokenID::NumericNotEquals
:
1193 return "NumericNotEquals";
1195 case TokenID::NumericLessThan
:
1196 return "NumericLessThan";
1198 case TokenID::NumericLessThanEquals
:
1199 return "NumericLessThanEquals";
1201 case TokenID::NumericGreaterThan
:
1202 return "NumericGreaterThan";
1204 case TokenID::NumericGreaterThanEquals
:
1205 return "NumericGreaterThanEquals";
1207 case TokenID::DateEquals
:
1208 return "DateEquals";
1210 case TokenID::DateNotEquals
:
1211 return "DateNotEquals";
1213 case TokenID::DateLessThan
:
1214 return "DateLessThan";
1216 case TokenID::DateLessThanEquals
:
1217 return "DateLessThanEquals";
1219 case TokenID::DateGreaterThan
:
1220 return "DateGreaterThan";
1222 case TokenID::DateGreaterThanEquals
:
1223 return "DateGreaterThanEquals";
1228 case TokenID::BinaryEquals
:
1229 return "BinaryEquals";
1231 case TokenID::IpAddress
:
1232 return "case TokenID::IpAddress";
1234 case TokenID::NotIpAddress
:
1235 return "NotIpAddress";
1237 case TokenID::ArnEquals
:
1240 case TokenID::ArnNotEquals
:
1241 return "ArnNotEquals";
1243 case TokenID::ArnLike
:
1246 case TokenID::ArnNotLike
:
1247 return "ArnNotLike";
1253 return "InvalidConditionOperator";
1257 template<typename Iterator
>
1258 ostream
& print_array(ostream
& m
, Iterator begin
, Iterator end
) {
1263 std::copy(begin
, end
, std::experimental::make_ostream_joiner(m
, ", "));
1269 template<typename Iterator
>
1270 ostream
& print_dict(ostream
& m
, Iterator begin
, Iterator end
) {
1272 std::copy(begin
, end
, std::experimental::make_ostream_joiner(m
, ", "));
1279 ostream
& operator <<(ostream
& m
, const Condition
& c
) {
1280 m
<< condop_string(c
.op
);
1284 m
<< ": { " << c
.key
;
1285 print_array(m
, c
.vals
.cbegin(), c
.vals
.cend());
1289 Effect
Statement::eval(const Environment
& e
,
1290 boost::optional
<const rgw::auth::Identity
&> ida
,
1291 uint64_t act
, const ARN
& res
) const {
1293 if (!princ
.empty() && !ida
->is_identity(princ
)) {
1294 return Effect::Pass
;
1295 } else if (!noprinc
.empty() && ida
->is_identity(noprinc
)) {
1296 return Effect::Pass
;
1300 if (!resource
.empty()) {
1301 if (!std::any_of(resource
.begin(), resource
.end(),
1302 [&res
](const ARN
& pattern
) {
1303 return pattern
.match(res
);
1305 return Effect::Pass
;
1307 } else if (!notresource
.empty()) {
1308 if (std::any_of(notresource
.begin(), notresource
.end(),
1309 [&res
](const ARN
& pattern
) {
1310 return pattern
.match(res
);
1312 return Effect::Pass
;
1316 if (!(action
[act
] == 1) || (notaction
[act
] == 1)) {
1317 return Effect::Pass
;
1320 if (std::all_of(conditions
.begin(),
1322 [&e
](const Condition
& c
) { return c
.eval(e
);})) {
1326 return Effect::Pass
;
1329 Effect
Statement::eval_principal(const Environment
& e
,
1330 boost::optional
<const rgw::auth::Identity
&> ida
) const {
1332 if (princ
.empty() && noprinc
.empty()) {
1333 return Effect::Deny
;
1335 if (!princ
.empty() && !ida
->is_identity(princ
)) {
1336 return Effect::Deny
;
1337 } else if (!noprinc
.empty() && ida
->is_identity(noprinc
)) {
1338 return Effect::Deny
;
1341 return Effect::Allow
;
1344 Effect
Statement::eval_conditions(const Environment
& e
) const {
1345 if (std::all_of(conditions
.begin(),
1347 [&e
](const Condition
& c
) { return c
.eval(e
);})) {
1348 return Effect::Allow
;
1350 return Effect::Deny
;
1354 const char* action_bit_string(uint64_t action
) {
1357 return "s3:GetObject";
1359 case s3GetObjectVersion
:
1360 return "s3:GetObjectVersion";
1363 return "s3:PutObject";
1365 case s3GetObjectAcl
:
1366 return "s3:GetObjectAcl";
1368 case s3GetObjectVersionAcl
:
1369 return "s3:GetObjectVersionAcl";
1371 case s3PutObjectAcl
:
1372 return "s3:PutObjectAcl";
1374 case s3PutObjectVersionAcl
:
1375 return "s3:PutObjectVersionAcl";
1377 case s3DeleteObject
:
1378 return "s3:DeleteObject";
1380 case s3DeleteObjectVersion
:
1381 return "s3:DeleteObjectVersion";
1383 case s3ListMultipartUploadParts
:
1384 return "s3:ListMultipartUploadParts";
1386 case s3AbortMultipartUpload
:
1387 return "s3:AbortMultipartUpload";
1389 case s3GetObjectTorrent
:
1390 return "s3:GetObjectTorrent";
1392 case s3GetObjectVersionTorrent
:
1393 return "s3:GetObjectVersionTorrent";
1395 case s3RestoreObject
:
1396 return "s3:RestoreObject";
1398 case s3CreateBucket
:
1399 return "s3:CreateBucket";
1401 case s3DeleteBucket
:
1402 return "s3:DeleteBucket";
1405 return "s3:ListBucket";
1407 case s3ListBucketVersions
:
1408 return "s3:ListBucketVersions";
1409 case s3ListAllMyBuckets
:
1410 return "s3:ListAllMyBuckets";
1412 case s3ListBucketMultipartUploads
:
1413 return "s3:ListBucketMultipartUploads";
1415 case s3GetAccelerateConfiguration
:
1416 return "s3:GetAccelerateConfiguration";
1418 case s3PutAccelerateConfiguration
:
1419 return "s3:PutAccelerateConfiguration";
1421 case s3GetBucketAcl
:
1422 return "s3:GetBucketAcl";
1424 case s3PutBucketAcl
:
1425 return "s3:PutBucketAcl";
1427 case s3GetBucketCORS
:
1428 return "s3:GetBucketCORS";
1430 case s3PutBucketCORS
:
1431 return "s3:PutBucketCORS";
1433 case s3GetBucketVersioning
:
1434 return "s3:GetBucketVersioning";
1436 case s3PutBucketVersioning
:
1437 return "s3:PutBucketVersioning";
1439 case s3GetBucketRequestPayment
:
1440 return "s3:GetBucketRequestPayment";
1442 case s3PutBucketRequestPayment
:
1443 return "s3:PutBucketRequestPayment";
1445 case s3GetBucketLocation
:
1446 return "s3:GetBucketLocation";
1448 case s3GetBucketPolicy
:
1449 return "s3:GetBucketPolicy";
1451 case s3DeleteBucketPolicy
:
1452 return "s3:DeleteBucketPolicy";
1454 case s3PutBucketPolicy
:
1455 return "s3:PutBucketPolicy";
1457 case s3GetBucketNotification
:
1458 return "s3:GetBucketNotification";
1460 case s3PutBucketNotification
:
1461 return "s3:PutBucketNotification";
1463 case s3GetBucketLogging
:
1464 return "s3:GetBucketLogging";
1466 case s3PutBucketLogging
:
1467 return "s3:PutBucketLogging";
1469 case s3GetBucketTagging
:
1470 return "s3:GetBucketTagging";
1472 case s3PutBucketTagging
:
1473 return "s3:PutBucketTagging";
1475 case s3GetBucketWebsite
:
1476 return "s3:GetBucketWebsite";
1478 case s3PutBucketWebsite
:
1479 return "s3:PutBucketWebsite";
1481 case s3DeleteBucketWebsite
:
1482 return "s3:DeleteBucketWebsite";
1484 case s3GetLifecycleConfiguration
:
1485 return "s3:GetLifecycleConfiguration";
1487 case s3PutLifecycleConfiguration
:
1488 return "s3:PutLifecycleConfiguration";
1490 case s3PutReplicationConfiguration
:
1491 return "s3:PutReplicationConfiguration";
1493 case s3GetReplicationConfiguration
:
1494 return "s3:GetReplicationConfiguration";
1496 case s3DeleteReplicationConfiguration
:
1497 return "s3:DeleteReplicationConfiguration";
1499 case s3PutObjectTagging
:
1500 return "s3:PutObjectTagging";
1502 case s3PutObjectVersionTagging
:
1503 return "s3:PutObjectVersionTagging";
1505 case s3GetObjectTagging
:
1506 return "s3:GetObjectTagging";
1508 case s3GetObjectVersionTagging
:
1509 return "s3:GetObjectVersionTagging";
1511 case s3DeleteObjectTagging
:
1512 return "s3:DeleteObjectTagging";
1514 case s3DeleteObjectVersionTagging
:
1515 return "s3:DeleteObjectVersionTagging";
1517 case iamPutUserPolicy
:
1518 return "iam:PutUserPolicy";
1520 case iamGetUserPolicy
:
1521 return "iam:GetUserPolicy";
1523 case iamListUserPolicies
:
1524 return "iam:ListUserPolicies";
1526 case iamDeleteUserPolicy
:
1527 return "iam:DeleteUserPolicy";
1530 return "iam:CreateRole";
1533 return "iam:DeleteRole";
1536 return "iam:GetRole";
1539 return "iam:ModifyRole";
1542 return "iam:ListRoles";
1544 case iamPutRolePolicy
:
1545 return "iam:PutRolePolicy";
1547 case iamGetRolePolicy
:
1548 return "iam:GetRolePolicy";
1550 case iamListRolePolicies
:
1551 return "iam:ListRolePolicies";
1553 case iamDeleteRolePolicy
:
1554 return "iam:DeleteRolePolicy";
1557 return "sts:AssumeRole";
1559 case stsAssumeRoleWithWebIdentity
:
1560 return "sts:AssumeRoleWithWebIdentity";
1562 case stsGetSessionToken
:
1563 return "sts:GetSessionToken";
1568 ostream
& print_actions(ostream
& m
, const Action_t a
) {
1571 for (auto i
= 0U; i
< allCount
; ++i
) {
1578 m
<< action_bit_string(i
);
1590 ostream
& operator <<(ostream
& m
, const Statement
& s
) {
1593 m
<< "Sid: " << *s
.sid
<< ", ";
1595 if (!s
.princ
.empty()) {
1597 print_dict(m
, s
.princ
.cbegin(), s
.princ
.cend());
1600 if (!s
.noprinc
.empty()) {
1601 m
<< "NotPrincipal: ";
1602 print_dict(m
, s
.noprinc
.cbegin(), s
.noprinc
.cend());
1607 (s
.effect
== Effect::Allow
?
1608 (const char*) "Allow" :
1609 (const char*) "Deny");
1611 if (s
.action
.any() || s
.notaction
.any() || !s
.resource
.empty() ||
1612 !s
.notresource
.empty() || !s
.conditions
.empty()) {
1616 if (s
.action
.any()) {
1618 print_actions(m
, s
.action
);
1620 if (s
.notaction
.any() || !s
.resource
.empty() ||
1621 !s
.notresource
.empty() || !s
.conditions
.empty()) {
1626 if (s
.notaction
.any()) {
1628 print_actions(m
, s
.notaction
);
1630 if (!s
.resource
.empty() || !s
.notresource
.empty() ||
1631 !s
.conditions
.empty()) {
1636 if (!s
.resource
.empty()) {
1638 print_array(m
, s
.resource
.cbegin(), s
.resource
.cend());
1640 if (!s
.notresource
.empty() || !s
.conditions
.empty()) {
1645 if (!s
.notresource
.empty()) {
1646 m
<< "NotResource: ";
1647 print_array(m
, s
.notresource
.cbegin(), s
.notresource
.cend());
1649 if (!s
.conditions
.empty()) {
1654 if (!s
.conditions
.empty()) {
1656 print_dict(m
, s
.conditions
.cbegin(), s
.conditions
.cend());
1662 Policy::Policy(CephContext
* cct
, const string
& tenant
,
1663 const bufferlist
& _text
)
1664 : text(_text
.to_str()) {
1665 StringStream
ss(text
.data());
1666 PolicyParser
pp(cct
, tenant
, *this);
1667 auto pr
= Reader
{}.Parse
<kParseNumbersAsStringsFlag
|
1668 kParseCommentsFlag
>(ss
, pp
);
1670 throw PolicyParseException(std::move(pr
));
1674 Effect
Policy::eval(const Environment
& e
,
1675 boost::optional
<const rgw::auth::Identity
&> ida
,
1676 std::uint64_t action
, const ARN
& resource
) const {
1677 auto allowed
= false;
1678 for (auto& s
: statements
) {
1679 auto g
= s
.eval(e
, ida
, action
, resource
);
1680 if (g
== Effect::Deny
) {
1682 } else if (g
== Effect::Allow
) {
1686 return allowed
? Effect::Allow
: Effect::Pass
;
1689 Effect
Policy::eval_principal(const Environment
& e
,
1690 boost::optional
<const rgw::auth::Identity
&> ida
) const {
1691 auto allowed
= false;
1692 for (auto& s
: statements
) {
1693 auto g
= s
.eval_principal(e
, ida
);
1694 if (g
== Effect::Deny
) {
1696 } else if (g
== Effect::Allow
) {
1700 return allowed
? Effect::Allow
: Effect::Deny
;
1703 Effect
Policy::eval_conditions(const Environment
& e
) const {
1704 auto allowed
= false;
1705 for (auto& s
: statements
) {
1706 auto g
= s
.eval_conditions(e
);
1707 if (g
== Effect::Deny
) {
1709 } else if (g
== Effect::Allow
) {
1713 return allowed
? Effect::Allow
: Effect::Deny
;
1716 ostream
& operator <<(ostream
& m
, const Policy
& p
) {
1718 << (p
.version
== Version::v2008_10_17
? "2008-10-17" : "2012-10-17");
1720 if (p
.id
|| !p
.statements
.empty()) {
1725 m
<< "Id: " << *p
.id
;
1726 if (!p
.statements
.empty()) {
1731 if (!p
.statements
.empty()) {
1732 m
<< "Statements: ";
1733 print_array(m
, p
.statements
.cbegin(), p
.statements
.cend());