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"
30 #include "rgw_basic_types.h"
31 #include "rgw_iam_policy_keywords.h"
33 #include "include/assert.h" // razzin' frazzin' ...grrr.
46 static constexpr std::uint64_t s3None
= 0;
47 static constexpr std::uint64_t s3GetObject
= 1ULL << 0;
48 static constexpr std::uint64_t s3GetObjectVersion
= 1ULL << 1;
49 static constexpr std::uint64_t s3PutObject
= 1ULL << 2;
50 static constexpr std::uint64_t s3GetObjectAcl
= 1ULL << 3;
51 static constexpr std::uint64_t s3GetObjectVersionAcl
= 1ULL << 4;
52 static constexpr std::uint64_t s3PutObjectAcl
= 1ULL << 5;
53 static constexpr std::uint64_t s3PutObjectVersionAcl
= 1ULL << 6;
54 static constexpr std::uint64_t s3DeleteObject
= 1ULL << 7;
55 static constexpr std::uint64_t s3DeleteObjectVersion
= 1ULL << 8;
56 static constexpr std::uint64_t s3ListMultipartUploadParts
= 1ULL << 9;
57 static constexpr std::uint64_t s3AbortMultipartUpload
= 1ULL << 10;
58 static constexpr std::uint64_t s3GetObjectTorrent
= 1ULL << 11;
59 static constexpr std::uint64_t s3GetObjectVersionTorrent
= 1ULL << 12;
60 static constexpr std::uint64_t s3RestoreObject
= 1ULL << 13;
61 static constexpr std::uint64_t s3CreateBucket
= 1ULL << 14;
62 static constexpr std::uint64_t s3DeleteBucket
= 1ULL << 15;
63 static constexpr std::uint64_t s3ListBucket
= 1ULL << 16;
64 static constexpr std::uint64_t s3ListBucketVersions
= 1ULL << 17;
65 static constexpr std::uint64_t s3ListAllMyBuckets
= 1ULL << 18;
66 static constexpr std::uint64_t s3ListBucketMultiPartUploads
= 1ULL << 19;
67 static constexpr std::uint64_t s3GetAccelerateConfiguration
= 1ULL << 20;
68 static constexpr std::uint64_t s3PutAccelerateConfiguration
= 1ULL << 21;
69 static constexpr std::uint64_t s3GetBucketAcl
= 1ULL << 22;
70 static constexpr std::uint64_t s3PutBucketAcl
= 1ULL << 23;
71 static constexpr std::uint64_t s3GetBucketCORS
= 1ULL << 24;
72 static constexpr std::uint64_t s3PutBucketCORS
= 1ULL << 25;
73 static constexpr std::uint64_t s3GetBucketVersioning
= 1ULL << 26;
74 static constexpr std::uint64_t s3PutBucketVersioning
= 1ULL << 27;
75 static constexpr std::uint64_t s3GetBucketRequestPayment
= 1ULL << 28;
76 static constexpr std::uint64_t s3PutBucketRequestPayment
= 1ULL << 29;
77 static constexpr std::uint64_t s3GetBucketLocation
= 1ULL << 30;
78 static constexpr std::uint64_t s3GetBucketPolicy
= 1ULL << 31;
79 static constexpr std::uint64_t s3DeleteBucketPolicy
= 1ULL << 32;
80 static constexpr std::uint64_t s3PutBucketPolicy
= 1ULL << 33;
81 static constexpr std::uint64_t s3GetBucketNotification
= 1ULL << 34;
82 static constexpr std::uint64_t s3PutBucketNotification
= 1ULL << 35;
83 static constexpr std::uint64_t s3GetBucketLogging
= 1ULL << 36;
84 static constexpr std::uint64_t s3PutBucketLogging
= 1ULL << 37;
85 static constexpr std::uint64_t s3GetBucketTagging
= 1ULL << 38;
86 static constexpr std::uint64_t s3PutBucketTagging
= 1ULL << 39;
87 static constexpr std::uint64_t s3GetBucketWebsite
= 1ULL << 40;
88 static constexpr std::uint64_t s3PutBucketWebsite
= 1ULL << 41;
89 static constexpr std::uint64_t s3DeleteBucketWebsite
= 1ULL << 42;
90 static constexpr std::uint64_t s3GetLifecycleConfiguration
= 1ULL << 43;
91 static constexpr std::uint64_t s3PutLifecycleConfiguration
= 1ULL << 44;
92 static constexpr std::uint64_t s3PutReplicationConfiguration
= 1ULL << 45;
93 static constexpr std::uint64_t s3GetReplicationConfiguration
= 1ULL << 46;
94 static constexpr std::uint64_t s3DeleteReplicationConfiguration
= 1ULL << 47;
95 static constexpr std::uint64_t s3GetObjectTagging
= 1ULL << 48;
96 static constexpr std::uint64_t s3PutObjectTagging
= 1ULL << 49;
97 static constexpr std::uint64_t s3DeleteObjectTagging
= 1ULL << 50;
98 static constexpr std::uint64_t s3GetObjectVersionTagging
= 1ULL << 51;
99 static constexpr std::uint64_t s3PutObjectVersionTagging
= 1ULL << 52;
100 static constexpr std::uint64_t s3DeleteObjectVersionTagging
= 1ULL << 53;
101 static constexpr std::uint64_t s3Count
= 54;
102 static constexpr std::uint64_t s3All
= (1ULL << s3Count
) - 1;
105 inline int op_to_perm(std::uint64_t op
) {
108 case s3GetObjectTorrent
:
109 case s3GetObjectVersion
:
110 case s3GetObjectVersionTorrent
:
111 case s3GetObjectTagging
:
112 case s3GetObjectVersionTagging
:
113 case s3ListAllMyBuckets
:
115 case s3ListBucketMultiPartUploads
:
116 case s3ListBucketVersions
:
117 case s3ListMultipartUploadParts
:
118 return RGW_PERM_READ
;
120 case s3AbortMultipartUpload
:
124 case s3DeleteObjectVersion
:
126 case s3PutObjectTagging
:
127 case s3PutObjectVersionTagging
:
128 case s3DeleteObjectTagging
:
129 case s3DeleteObjectVersionTagging
:
130 case s3RestoreObject
:
131 return RGW_PERM_WRITE
;
133 case s3GetAccelerateConfiguration
:
135 case s3GetBucketCORS
:
136 case s3GetBucketLocation
:
137 case s3GetBucketLogging
:
138 case s3GetBucketNotification
:
139 case s3GetBucketPolicy
:
140 case s3GetBucketRequestPayment
:
141 case s3GetBucketTagging
:
142 case s3GetBucketVersioning
:
143 case s3GetBucketWebsite
:
144 case s3GetLifecycleConfiguration
:
146 case s3GetObjectVersionAcl
:
147 case s3GetReplicationConfiguration
:
148 return RGW_PERM_READ_ACP
;
150 case s3DeleteBucketPolicy
:
151 case s3DeleteBucketWebsite
:
152 case s3DeleteReplicationConfiguration
:
153 case s3PutAccelerateConfiguration
:
155 case s3PutBucketCORS
:
156 case s3PutBucketLogging
:
157 case s3PutBucketNotification
:
158 case s3PutBucketPolicy
:
159 case s3PutBucketRequestPayment
:
160 case s3PutBucketTagging
:
161 case s3PutBucketVersioning
:
162 case s3PutBucketWebsite
:
163 case s3PutLifecycleConfiguration
:
165 case s3PutObjectVersionAcl
:
166 case s3PutReplicationConfiguration
:
167 return RGW_PERM_WRITE_ACP
;
170 return RGW_PERM_FULL_CONTROL
;
172 return RGW_PERM_INVALID
;
176 using Environment
= boost::container::flat_map
<std::string
, std::string
>;
178 enum struct Partition
{
179 aws
, aws_cn
, aws_us_gov
, wildcard
180 // If we wanted our own ARNs for principal type unique to us
181 // (maybe to integrate better with Swift) or for anything else we
182 // provide that doesn't map onto S3, we could add an 'rgw'
186 enum struct Service
{
187 apigateway
, appstream
, artifact
, autoscaling
, aws_portal
, acm
,
188 cloudformation
, cloudfront
, cloudhsm
, cloudsearch
, cloudtrail
,
189 cloudwatch
, events
, logs
, codebuild
, codecommit
, codedeploy
,
190 codepipeline
, cognito_idp
, cognito_identity
, cognito_sync
,
191 config
, datapipeline
, dms
, devicefarm
, directconnect
,
192 ds
, dynamodb
, ec2
, ecr
, ecs
, ssm
, elasticbeanstalk
, elasticfilesystem
,
193 elasticloadbalancing
, elasticmapreduce
, elastictranscoder
, elasticache
,
194 es
, gamelift
, glacier
, health
, iam
, importexport
, inspector
, iot
,
195 kms
, kinesisanalytics
, firehose
, kinesis
, lambda
, lightsail
,
196 machinelearning
, aws_marketplace
, aws_marketplace_management
,
197 mobileanalytics
, mobilehub
, opsworks
, opsworks_cm
, polly
,
198 redshift
, rds
, route53
, route53domains
, sts
, servicecatalog
,
199 ses
, sns
, sqs
, s3
, swf
, sdb
, states
, storagegateway
, support
,
200 trustedadvisor
, waf
, workmail
, workspaces
, wildcard
207 // Once we refity tenant, we should probably use that instead of a
210 std::string resource
;
213 : partition(Partition::wildcard
), service(Service::wildcard
) {}
214 ARN(Partition partition
, Service service
, std::string region
,
215 std::string account
, std::string resource
)
216 : partition(partition
), service(service
), region(std::move(region
)),
217 account(std::move(account
)), resource(std::move(resource
)) {}
218 ARN(const rgw_obj
& o
);
219 ARN(const rgw_bucket
& b
);
220 ARN(const rgw_bucket
& b
, const std::string
& o
);
222 static boost::optional
<ARN
> parse(const std::string
& s
,
223 bool wildcard
= false);
224 std::string
to_string() const;
226 // `this` is the pattern
227 bool match(const ARN
& candidate
) const;
230 inline std::string
to_string(const ARN
& a
) {
231 return a
.to_string();
234 inline std::ostream
& operator <<(std::ostream
& m
, const ARN
& a
) {
235 return m
<< to_string(a
);
238 bool operator ==(const ARN
& l
, const ARN
& r
);
239 bool operator <(const ARN
& l
, const ARN
& r
);
241 using Address
= std::bitset
<128>;
245 // Since we're mapping IPv6 to IPv4 addresses, we may want to
246 // consider making the prefix always be in terms of a v6 address
247 // and just use the v6 bit to rewrite it as a v4 prefix for
252 std::ostream
& operator <<(std::ostream
& m
, const MaskedIP
& ip
);
253 string
to_string(const MaskedIP
& m
);
255 inline bool operator ==(const MaskedIP
& l
, const MaskedIP
& r
) {
256 auto shift
= std::max((l
.v6
? 128 : 32) - l
.prefix
,
257 (r
.v6
? 128 : 32) - r
.prefix
);
258 ceph_assert(shift
> 0);
259 return (l
.addr
>> shift
) == (r
.addr
>> shift
);
264 // Originally I was going to use a perfect hash table, but Marcus
265 // says keys are to be added at run-time not compile time.
267 // In future development, use symbol internment.
269 bool ifexists
= false;
270 // Much to my annoyance there is no actual way to do this in a
271 // typed way that is compatible with AWS. I know this because I've
272 // seen examples where the same value is used as a string in one
273 // context and a date in another.
274 std::vector
<std::string
> vals
;
276 Condition() = default;
277 Condition(TokenID op
, const char* s
, std::size_t len
, bool ifexists
)
278 : op(op
), key(s
, len
), ifexists(ifexists
) {}
280 bool eval(const Environment
& e
) const;
282 static boost::optional
<double> as_number(const std::string
& s
) {
286 double d
= std::stod(s
, &p
);
287 if (p
< s
.length()) {
292 } catch (const std::logic_error
& e
) {
297 static boost::optional
<ceph::real_time
> as_date(const std::string
& s
) {
301 double d
= std::stod(s
, &p
);
302 if (p
== s
.length()) {
303 return ceph::real_time(
304 std::chrono::seconds(static_cast<uint64_t>(d
)) +
305 std::chrono::nanoseconds(
306 static_cast<uint64_t>((d
- static_cast<uint64_t>(d
))
310 return from_iso_8601(boost::string_ref(s
), false);
311 } catch (const std::logic_error
& e
) {
316 static boost::optional
<bool> as_bool(const std::string
& s
) {
319 if (s
.empty() || boost::iequals(s
, "false")) {
324 double d
= std::stod(s
, &p
);
325 if (p
== s
.length()) {
326 return !((d
== +0.0) || (d
== -0.0) || std::isnan(d
));
328 } catch (const std::logic_error
& e
) {
335 static boost::optional
<ceph::bufferlist
> as_binary(const std::string
& s
) {
337 ceph::bufferlist base64
;
338 // I could populate a bufferlist
339 base64
.push_back(buffer::create_static(
341 const_cast<char*>(s
.data()))); // Yuck
342 // From a base64 encoded std::string.
343 ceph::bufferlist bin
;
346 base64
.decode_base64(bin
);
347 } catch (const ceph::buffer::malformed_input
& e
) {
353 static boost::optional
<MaskedIP
> as_network(const std::string
& s
);
356 struct ci_equal_to
: public std::binary_function
<const std::string
,
359 bool operator ()(const std::string
& s1
,
360 const std::string
& s2
) const {
361 return boost::iequals(s1
, s2
);
367 static bool orrible(F
&& f
, const std::string
& c
,
368 const std::vector
<std::string
>& v
) {
369 for (const auto& d
: v
) {
370 if (std::forward
<F
>(f
)(c
, d
)) {
377 template<typename F
, typename X
>
378 static bool shortible(F
&& f
, X
& x
, const std::string
& c
,
379 const std::vector
<std::string
>& v
) {
380 auto xc
= std::forward
<X
>(x
)(c
);
385 for (const auto& d
: v
) {
386 auto xd
= std::forward
<X
>(x
)(d
);
391 if (std::forward
<F
>(f
)(*xc
, *xd
)) {
399 std::ostream
& operator <<(std::ostream
& m
, const Condition
& c
);
401 std::string
to_string(const Condition
& c
);
404 boost::optional
<std::string
> sid
= boost::none
;
406 boost::container::flat_set
<rgw::auth::Principal
> princ
;
407 boost::container::flat_set
<rgw::auth::Principal
> noprinc
;
409 // Every statement MUST provide an effect. I just initialize it to
410 // deny as defensive programming.
411 Effect effect
= Effect::Deny
;
413 std::uint64_t action
= 0;
414 std::uint64_t notaction
= 0;
416 boost::container::flat_set
<ARN
> resource
;
417 boost::container::flat_set
<ARN
> notresource
;
419 std::vector
<Condition
> conditions
;
421 Effect
eval(const Environment
& e
,
422 boost::optional
<const rgw::auth::Identity
&> ida
,
423 std::uint64_t action
, const ARN
& resource
) const;
426 std::ostream
& operator <<(ostream
& m
, const Statement
& s
);
427 std::string
to_string(const Statement
& s
);
429 struct PolicyParseException
: public std::exception
{
430 rapidjson::ParseResult pr
;
432 PolicyParseException(rapidjson::ParseResult
&& pr
)
434 const char* what() const noexcept override
{
435 return rapidjson::GetParseError_En(pr
.Code());
441 Version version
= Version::v2008_10_17
;
442 boost::optional
<std::string
> id
= boost::none
;
444 std::vector
<Statement
> statements
;
446 Policy(CephContext
* cct
, const std::string
& tenant
,
447 const bufferlist
& text
);
449 Effect
eval(const Environment
& e
,
450 boost::optional
<const rgw::auth::Identity
&> ida
,
451 std::uint64_t action
, const ARN
& resource
) const;
454 std::ostream
& operator <<(ostream
& m
, const Policy
& p
);
455 std::string
to_string(const Policy
& p
);
461 struct hash
<::rgw::IAM::Service
> {
462 size_t operator()(const ::rgw::IAM::Service
& s
) const noexcept
{
463 // Invoke a default-constructed hash object for int.
464 return hash
<int>()(static_cast<int>(s
));