1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #ifndef CEPH_RGW_IAM_POLICY_H
5 #define CEPH_RGW_IAM_POLICY_H
13 #include <boost/algorithm/string/predicate.hpp>
14 #include <boost/container/flat_map.hpp>
15 #include <boost/container/flat_set.hpp>
16 #include <boost/optional.hpp>
17 #include <boost/thread/shared_mutex.hpp>
18 #include <boost/utility/string_ref.hpp>
19 #include <boost/variant.hpp>
21 #include "common/ceph_time.h"
22 #include "common/iso_8601.h"
24 #include "rapidjson/error/error.h"
25 #include "rapidjson/error/en.h"
28 #include "rgw_basic_types.h"
29 #include "rgw_iam_policy_keywords.h"
30 #include "rgw_string.h"
32 #include "include/assert.h" // razzin' frazzin' ...grrr.
45 static constexpr std::uint64_t s3None
= 0;
46 static constexpr std::uint64_t s3GetObject
= 1ULL << 0;
47 static constexpr std::uint64_t s3GetObjectVersion
= 1ULL << 1;
48 static constexpr std::uint64_t s3PutObject
= 1ULL << 2;
49 static constexpr std::uint64_t s3GetObjectAcl
= 1ULL << 3;
50 static constexpr std::uint64_t s3GetObjectVersionAcl
= 1ULL << 4;
51 static constexpr std::uint64_t s3PutObjectAcl
= 1ULL << 5;
52 static constexpr std::uint64_t s3PutObjectVersionAcl
= 1ULL << 6;
53 static constexpr std::uint64_t s3DeleteObject
= 1ULL << 7;
54 static constexpr std::uint64_t s3DeleteObjectVersion
= 1ULL << 8;
55 static constexpr std::uint64_t s3ListMultipartUploadParts
= 1ULL << 9;
56 static constexpr std::uint64_t s3AbortMultipartUpload
= 1ULL << 10;
57 static constexpr std::uint64_t s3GetObjectTorrent
= 1ULL << 11;
58 static constexpr std::uint64_t s3GetObjectVersionTorrent
= 1ULL << 12;
59 static constexpr std::uint64_t s3RestoreObject
= 1ULL << 13;
60 static constexpr std::uint64_t s3CreateBucket
= 1ULL << 14;
61 static constexpr std::uint64_t s3DeleteBucket
= 1ULL << 15;
62 static constexpr std::uint64_t s3ListBucket
= 1ULL << 16;
63 static constexpr std::uint64_t s3ListBucketVersions
= 1ULL << 17;
64 static constexpr std::uint64_t s3ListAllMyBuckets
= 1ULL << 18;
65 static constexpr std::uint64_t s3ListBucketMultiPartUploads
= 1ULL << 19;
66 static constexpr std::uint64_t s3GetAccelerateConfiguration
= 1ULL << 20;
67 static constexpr std::uint64_t s3PutAccelerateConfiguration
= 1ULL << 21;
68 static constexpr std::uint64_t s3GetBucketAcl
= 1ULL << 22;
69 static constexpr std::uint64_t s3PutBucketAcl
= 1ULL << 23;
70 static constexpr std::uint64_t s3GetBucketCORS
= 1ULL << 24;
71 static constexpr std::uint64_t s3PutBucketCORS
= 1ULL << 25;
72 static constexpr std::uint64_t s3GetBucketVersioning
= 1ULL << 26;
73 static constexpr std::uint64_t s3PutBucketVersioning
= 1ULL << 27;
74 static constexpr std::uint64_t s3GetBucketRequestPayment
= 1ULL << 28;
75 static constexpr std::uint64_t s3PutBucketRequestPayment
= 1ULL << 29;
76 static constexpr std::uint64_t s3GetBucketLocation
= 1ULL << 30;
77 static constexpr std::uint64_t s3GetBucketPolicy
= 1ULL << 31;
78 static constexpr std::uint64_t s3DeleteBucketPolicy
= 1ULL << 32;
79 static constexpr std::uint64_t s3PutBucketPolicy
= 1ULL << 33;
80 static constexpr std::uint64_t s3GetBucketNotification
= 1ULL << 34;
81 static constexpr std::uint64_t s3PutBucketNotification
= 1ULL << 35;
82 static constexpr std::uint64_t s3GetBucketLogging
= 1ULL << 36;
83 static constexpr std::uint64_t s3PutBucketLogging
= 1ULL << 37;
84 static constexpr std::uint64_t s3GetBucketTagging
= 1ULL << 38;
85 static constexpr std::uint64_t s3PutBucketTagging
= 1ULL << 39;
86 static constexpr std::uint64_t s3GetBucketWebsite
= 1ULL << 40;
87 static constexpr std::uint64_t s3PutBucketWebsite
= 1ULL << 41;
88 static constexpr std::uint64_t s3DeleteBucketWebsite
= 1ULL << 42;
89 static constexpr std::uint64_t s3GetLifecycleConfiguration
= 1ULL << 43;
90 static constexpr std::uint64_t s3PutLifecycleConfiguration
= 1ULL << 44;
91 static constexpr std::uint64_t s3PutReplicationConfiguration
= 1ULL << 45;
92 static constexpr std::uint64_t s3GetReplicationConfiguration
= 1ULL << 46;
93 static constexpr std::uint64_t s3DeleteReplicationConfiguration
= 1ULL << 47;
94 static constexpr std::uint64_t s3GetObjectTagging
= 1ULL << 48;
95 static constexpr std::uint64_t s3PutObjectTagging
= 1ULL << 49;
96 static constexpr std::uint64_t s3DeleteObjectTagging
= 1ULL << 50;
97 static constexpr std::uint64_t s3GetObjectVersionTagging
= 1ULL << 51;
98 static constexpr std::uint64_t s3PutObjectVersionTagging
= 1ULL << 52;
99 static constexpr std::uint64_t s3DeleteObjectVersionTagging
= 1ULL << 53;
100 static constexpr std::uint64_t s3Count
= 54;
101 static constexpr std::uint64_t s3All
= (1ULL << s3Count
) - 1;
104 inline int op_to_perm(std::uint64_t op
) {
107 case s3GetObjectTorrent
:
108 case s3GetObjectVersion
:
109 case s3GetObjectVersionTorrent
:
110 case s3GetObjectTagging
:
111 case s3GetObjectVersionTagging
:
112 case s3ListAllMyBuckets
:
114 case s3ListBucketMultiPartUploads
:
115 case s3ListBucketVersions
:
116 case s3ListMultipartUploadParts
:
117 return RGW_PERM_READ
;
119 case s3AbortMultipartUpload
:
123 case s3DeleteObjectVersion
:
125 case s3PutObjectTagging
:
126 case s3PutObjectVersionTagging
:
127 case s3DeleteObjectTagging
:
128 case s3DeleteObjectVersionTagging
:
129 case s3RestoreObject
:
130 return RGW_PERM_WRITE
;
132 case s3GetAccelerateConfiguration
:
134 case s3GetBucketCORS
:
135 case s3GetBucketLocation
:
136 case s3GetBucketLogging
:
137 case s3GetBucketNotification
:
138 case s3GetBucketPolicy
:
139 case s3GetBucketRequestPayment
:
140 case s3GetBucketTagging
:
141 case s3GetBucketVersioning
:
142 case s3GetBucketWebsite
:
143 case s3GetLifecycleConfiguration
:
145 case s3GetObjectVersionAcl
:
146 case s3GetReplicationConfiguration
:
147 return RGW_PERM_READ_ACP
;
149 case s3DeleteBucketPolicy
:
150 case s3DeleteBucketWebsite
:
151 case s3DeleteReplicationConfiguration
:
152 case s3PutAccelerateConfiguration
:
154 case s3PutBucketCORS
:
155 case s3PutBucketLogging
:
156 case s3PutBucketNotification
:
157 case s3PutBucketPolicy
:
158 case s3PutBucketRequestPayment
:
159 case s3PutBucketTagging
:
160 case s3PutBucketVersioning
:
161 case s3PutBucketWebsite
:
162 case s3PutLifecycleConfiguration
:
164 case s3PutObjectVersionAcl
:
165 case s3PutReplicationConfiguration
:
166 return RGW_PERM_WRITE_ACP
;
169 return RGW_PERM_FULL_CONTROL
;
171 return RGW_PERM_INVALID
;
175 using Environment
= boost::container::flat_map
<std::string
, std::string
>;
177 enum struct Partition
{
178 aws
, aws_cn
, aws_us_gov
, wildcard
179 // If we wanted our own ARNs for principal type unique to us
180 // (maybe to integrate better with Swift) or for anything else we
181 // provide that doesn't map onto S3, we could add an 'rgw'
185 enum struct Service
{
186 apigateway
, appstream
, artifact
, autoscaling
, aws_portal
, acm
,
187 cloudformation
, cloudfront
, cloudhsm
, cloudsearch
, cloudtrail
,
188 cloudwatch
, events
, logs
, codebuild
, codecommit
, codedeploy
,
189 codepipeline
, cognito_idp
, cognito_identity
, cognito_sync
,
190 config
, datapipeline
, dms
, devicefarm
, directconnect
,
191 ds
, dynamodb
, ec2
, ecr
, ecs
, ssm
, elasticbeanstalk
, elasticfilesystem
,
192 elasticloadbalancing
, elasticmapreduce
, elastictranscoder
, elasticache
,
193 es
, gamelift
, glacier
, health
, iam
, importexport
, inspector
, iot
,
194 kms
, kinesisanalytics
, firehose
, kinesis
, lambda
, lightsail
,
195 machinelearning
, aws_marketplace
, aws_marketplace_management
,
196 mobileanalytics
, mobilehub
, opsworks
, opsworks_cm
, polly
,
197 redshift
, rds
, route53
, route53domains
, sts
, servicecatalog
,
198 ses
, sns
, sqs
, s3
, swf
, sdb
, states
, storagegateway
, support
,
199 trustedadvisor
, waf
, workmail
, workspaces
, wildcard
206 // Once we refity tenant, we should probably use that instead of a
209 std::string resource
;
212 : partition(Partition::wildcard
), service(Service::wildcard
) {}
213 ARN(Partition partition
, Service service
, std::string region
,
214 std::string account
, std::string resource
)
215 : partition(partition
), service(service
), region(std::move(region
)),
216 account(std::move(account
)), resource(std::move(resource
)) {}
217 ARN(const rgw_obj
& o
);
218 ARN(const rgw_bucket
& b
);
219 ARN(const rgw_bucket
& b
, const std::string
& o
);
221 static boost::optional
<ARN
> parse(const std::string
& s
,
222 bool wildcard
= false);
223 std::string
to_string() const;
225 // `this` is the pattern
226 bool match(const ARN
& candidate
) const;
229 inline std::string
to_string(const ARN
& a
) {
230 return a
.to_string();
233 inline std::ostream
& operator <<(std::ostream
& m
, const ARN
& a
) {
234 return m
<< to_string(a
);
237 bool operator ==(const ARN
& l
, const ARN
& r
);
238 bool operator <(const ARN
& l
, const ARN
& r
);
240 using Address
= std::bitset
<128>;
244 // Since we're mapping IPv6 to IPv4 addresses, we may want to
245 // consider making the prefix always be in terms of a v6 address
246 // and just use the v6 bit to rewrite it as a v4 prefix for
251 std::ostream
& operator <<(std::ostream
& m
, const MaskedIP
& ip
);
252 string
to_string(const MaskedIP
& m
);
254 inline bool operator ==(const MaskedIP
& l
, const MaskedIP
& r
) {
255 auto shift
= std::max((l
.v6
? 128 : 32) - l
.prefix
,
256 (r
.v6
? 128 : 32) - r
.prefix
);
257 ceph_assert(shift
> 0);
258 return (l
.addr
>> shift
) == (r
.addr
>> shift
);
263 // Originally I was going to use a perfect hash table, but Marcus
264 // says keys are to be added at run-time not compile time.
266 // In future development, use symbol internment.
268 bool ifexists
= false;
269 // Much to my annoyance there is no actual way to do this in a
270 // typed way that is compatible with AWS. I know this because I've
271 // seen examples where the same value is used as a string in one
272 // context and a date in another.
273 std::vector
<std::string
> vals
;
275 Condition() = default;
276 Condition(TokenID op
, const char* s
, std::size_t len
, bool ifexists
)
277 : op(op
), key(s
, len
), ifexists(ifexists
) {}
279 bool eval(const Environment
& e
) const;
281 static boost::optional
<double> as_number(const std::string
& s
) {
285 double d
= std::stod(s
, &p
);
286 if (p
< s
.length()) {
291 } catch (const std::logic_error
& e
) {
296 static boost::optional
<ceph::real_time
> as_date(const std::string
& s
) {
300 double d
= std::stod(s
, &p
);
301 if (p
== s
.length()) {
302 return ceph::real_time(
303 std::chrono::seconds(static_cast<uint64_t>(d
)) +
304 std::chrono::nanoseconds(
305 static_cast<uint64_t>((d
- static_cast<uint64_t>(d
))
309 return from_iso_8601(boost::string_ref(s
), false);
310 } catch (const std::logic_error
& e
) {
315 static boost::optional
<bool> as_bool(const std::string
& s
) {
318 if (s
.empty() || boost::iequals(s
, "false")) {
323 double d
= std::stod(s
, &p
);
324 if (p
== s
.length()) {
325 return !((d
== +0.0) || (d
== -0.0) || std::isnan(d
));
327 } catch (const std::logic_error
& e
) {
334 static boost::optional
<ceph::bufferlist
> as_binary(const std::string
& s
) {
336 ceph::bufferlist base64
;
337 // I could populate a bufferlist
338 base64
.push_back(buffer::create_static(
340 const_cast<char*>(s
.data()))); // Yuck
341 // From a base64 encoded std::string.
342 ceph::bufferlist bin
;
345 base64
.decode_base64(bin
);
346 } catch (const ceph::buffer::malformed_input
& e
) {
352 static boost::optional
<MaskedIP
> as_network(const std::string
& s
);
356 bool operator ()(const std::string
& s1
,
357 const std::string
& s2
) const {
358 return boost::iequals(s1
, s2
);
363 bool operator ()(const std::string
& input
,
364 const std::string
& pattern
) const {
365 return match_wildcards(pattern
, input
, 0);
370 static bool orrible(F
&& f
, const std::string
& c
,
371 const std::vector
<std::string
>& v
) {
372 for (const auto& d
: v
) {
373 if (std::forward
<F
>(f
)(c
, d
)) {
380 template<typename F
, typename X
>
381 static bool shortible(F
&& f
, X
& x
, const std::string
& c
,
382 const std::vector
<std::string
>& v
) {
383 auto xc
= std::forward
<X
>(x
)(c
);
388 for (const auto& d
: v
) {
389 auto xd
= std::forward
<X
>(x
)(d
);
394 if (std::forward
<F
>(f
)(*xc
, *xd
)) {
402 std::ostream
& operator <<(std::ostream
& m
, const Condition
& c
);
404 std::string
to_string(const Condition
& c
);
407 boost::optional
<std::string
> sid
= boost::none
;
409 boost::container::flat_set
<rgw::auth::Principal
> princ
;
410 boost::container::flat_set
<rgw::auth::Principal
> noprinc
;
412 // Every statement MUST provide an effect. I just initialize it to
413 // deny as defensive programming.
414 Effect effect
= Effect::Deny
;
416 std::uint64_t action
= 0;
417 std::uint64_t notaction
= 0;
419 boost::container::flat_set
<ARN
> resource
;
420 boost::container::flat_set
<ARN
> notresource
;
422 std::vector
<Condition
> conditions
;
424 Effect
eval(const Environment
& e
,
425 boost::optional
<const rgw::auth::Identity
&> ida
,
426 std::uint64_t action
, const ARN
& resource
) const;
429 std::ostream
& operator <<(ostream
& m
, const Statement
& s
);
430 std::string
to_string(const Statement
& s
);
432 struct PolicyParseException
: public std::exception
{
433 rapidjson::ParseResult pr
;
435 PolicyParseException(rapidjson::ParseResult
&& pr
)
437 const char* what() const noexcept override
{
438 return rapidjson::GetParseError_En(pr
.Code());
444 Version version
= Version::v2008_10_17
;
445 boost::optional
<std::string
> id
= boost::none
;
447 std::vector
<Statement
> statements
;
449 Policy(CephContext
* cct
, const std::string
& tenant
,
450 const bufferlist
& text
);
452 Effect
eval(const Environment
& e
,
453 boost::optional
<const rgw::auth::Identity
&> ida
,
454 std::uint64_t action
, const ARN
& resource
) const;
457 std::ostream
& operator <<(ostream
& m
, const Policy
& p
);
458 std::string
to_string(const Policy
& p
);
464 struct hash
<::rgw::IAM::Service
> {
465 size_t operator()(const ::rgw::IAM::Service
& s
) const noexcept
{
466 // Invoke a default-constructed hash object for int.
467 return hash
<int>()(static_cast<int>(s
));