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"
43 static constexpr std::uint64_t s3None = 0;
44 static constexpr std::uint64_t s3GetObject = 1ULL << 0;
45 static constexpr std::uint64_t s3GetObjectVersion = 1ULL << 1;
46 static constexpr std::uint64_t s3PutObject = 1ULL << 2;
47 static constexpr std::uint64_t s3GetObjectAcl = 1ULL << 3;
48 static constexpr std::uint64_t s3GetObjectVersionAcl = 1ULL << 4;
49 static constexpr std::uint64_t s3PutObjectAcl = 1ULL << 5;
50 static constexpr std::uint64_t s3PutObjectVersionAcl = 1ULL << 6;
51 static constexpr std::uint64_t s3DeleteObject = 1ULL << 7;
52 static constexpr std::uint64_t s3DeleteObjectVersion = 1ULL << 8;
53 static constexpr std::uint64_t s3ListMultipartUploadParts = 1ULL << 9;
54 static constexpr std::uint64_t s3AbortMultipartUpload = 1ULL << 10;
55 static constexpr std::uint64_t s3GetObjectTorrent = 1ULL << 11;
56 static constexpr std::uint64_t s3GetObjectVersionTorrent = 1ULL << 12;
57 static constexpr std::uint64_t s3RestoreObject = 1ULL << 13;
58 static constexpr std::uint64_t s3CreateBucket = 1ULL << 14;
59 static constexpr std::uint64_t s3DeleteBucket = 1ULL << 15;
60 static constexpr std::uint64_t s3ListBucket = 1ULL << 16;
61 static constexpr std::uint64_t s3ListBucketVersions = 1ULL << 17;
62 static constexpr std::uint64_t s3ListAllMyBuckets = 1ULL << 18;
63 static constexpr std::uint64_t s3ListBucketMultiPartUploads = 1ULL << 19;
64 static constexpr std::uint64_t s3GetAccelerateConfiguration = 1ULL << 20;
65 static constexpr std::uint64_t s3PutAccelerateConfiguration = 1ULL << 21;
66 static constexpr std::uint64_t s3GetBucketAcl = 1ULL << 22;
67 static constexpr std::uint64_t s3PutBucketAcl = 1ULL << 23;
68 static constexpr std::uint64_t s3GetBucketCORS = 1ULL << 24;
69 static constexpr std::uint64_t s3PutBucketCORS = 1ULL << 25;
70 static constexpr std::uint64_t s3GetBucketVersioning = 1ULL << 26;
71 static constexpr std::uint64_t s3PutBucketVersioning = 1ULL << 27;
72 static constexpr std::uint64_t s3GetBucketRequestPayment = 1ULL << 28;
73 static constexpr std::uint64_t s3PutBucketRequestPayment = 1ULL << 29;
74 static constexpr std::uint64_t s3GetBucketLocation = 1ULL << 30;
75 static constexpr std::uint64_t s3GetBucketPolicy = 1ULL << 31;
76 static constexpr std::uint64_t s3DeleteBucketPolicy = 1ULL << 32;
77 static constexpr std::uint64_t s3PutBucketPolicy = 1ULL << 33;
78 static constexpr std::uint64_t s3GetBucketNotification = 1ULL << 34;
79 static constexpr std::uint64_t s3PutBucketNotification = 1ULL << 35;
80 static constexpr std::uint64_t s3GetBucketLogging = 1ULL << 36;
81 static constexpr std::uint64_t s3PutBucketLogging = 1ULL << 37;
82 static constexpr std::uint64_t s3GetBucketTagging = 1ULL << 38;
83 static constexpr std::uint64_t s3PutBucketTagging = 1ULL << 39;
84 static constexpr std::uint64_t s3GetBucketWebsite = 1ULL << 40;
85 static constexpr std::uint64_t s3PutBucketWebsite = 1ULL << 41;
86 static constexpr std::uint64_t s3DeleteBucketWebsite = 1ULL << 42;
87 static constexpr std::uint64_t s3GetLifecycleConfiguration = 1ULL << 43;
88 static constexpr std::uint64_t s3PutLifecycleConfiguration = 1ULL << 44;
89 static constexpr std::uint64_t s3PutReplicationConfiguration = 1ULL << 45;
90 static constexpr std::uint64_t s3GetReplicationConfiguration = 1ULL << 46;
91 static constexpr std::uint64_t s3DeleteReplicationConfiguration = 1ULL << 47;
92 static constexpr std::uint64_t s3GetObjectTagging = 1ULL << 48;
93 static constexpr std::uint64_t s3PutObjectTagging = 1ULL << 49;
94 static constexpr std::uint64_t s3DeleteObjectTagging = 1ULL << 50;
95 static constexpr std::uint64_t s3GetObjectVersionTagging = 1ULL << 51;
96 static constexpr std::uint64_t s3PutObjectVersionTagging = 1ULL << 52;
97 static constexpr std::uint64_t s3DeleteObjectVersionTagging = 1ULL << 53;
98 static constexpr std::uint64_t s3Count = 54;
99 static constexpr std::uint64_t s3All = (1ULL << s3Count) - 1;
102 inline int op_to_perm(std::uint64_t op) {
105 case s3GetObjectTorrent:
106 case s3GetObjectVersion:
107 case s3GetObjectVersionTorrent:
108 case s3GetObjectTagging:
109 case s3GetObjectVersionTagging:
110 case s3ListAllMyBuckets:
112 case s3ListBucketMultiPartUploads:
113 case s3ListBucketVersions:
114 case s3ListMultipartUploadParts:
115 return RGW_PERM_READ;
117 case s3AbortMultipartUpload:
121 case s3DeleteObjectVersion:
123 case s3PutObjectTagging:
124 case s3PutObjectVersionTagging:
125 case s3DeleteObjectTagging:
126 case s3DeleteObjectVersionTagging:
127 case s3RestoreObject:
128 return RGW_PERM_WRITE;
130 case s3GetAccelerateConfiguration:
132 case s3GetBucketCORS:
133 case s3GetBucketLocation:
134 case s3GetBucketLogging:
135 case s3GetBucketNotification:
136 case s3GetBucketPolicy:
137 case s3GetBucketRequestPayment:
138 case s3GetBucketTagging:
139 case s3GetBucketVersioning:
140 case s3GetBucketWebsite:
141 case s3GetLifecycleConfiguration:
143 case s3GetObjectVersionAcl:
144 case s3GetReplicationConfiguration:
145 return RGW_PERM_READ_ACP;
147 case s3DeleteBucketPolicy:
148 case s3DeleteBucketWebsite:
149 case s3DeleteReplicationConfiguration:
150 case s3PutAccelerateConfiguration:
152 case s3PutBucketCORS:
153 case s3PutBucketLogging:
154 case s3PutBucketNotification:
155 case s3PutBucketPolicy:
156 case s3PutBucketRequestPayment:
157 case s3PutBucketTagging:
158 case s3PutBucketVersioning:
159 case s3PutBucketWebsite:
160 case s3PutLifecycleConfiguration:
162 case s3PutObjectVersionAcl:
163 case s3PutReplicationConfiguration:
164 return RGW_PERM_WRITE_ACP;
167 return RGW_PERM_FULL_CONTROL;
169 return RGW_PERM_INVALID;
173 using Environment = boost::container::flat_map<std::string, std::string>;
175 enum struct Partition {
176 aws, aws_cn, aws_us_gov, wildcard
177 // If we wanted our own ARNs for principal type unique to us
178 // (maybe to integrate better with Swift) or for anything else we
179 // provide that doesn't map onto S3, we could add an 'rgw'
183 enum struct Service {
184 apigateway, appstream, artifact, autoscaling, aws_portal, acm,
185 cloudformation, cloudfront, cloudhsm, cloudsearch, cloudtrail,
186 cloudwatch, events, logs, codebuild, codecommit, codedeploy,
187 codepipeline, cognito_idp, cognito_identity, cognito_sync,
188 config, datapipeline, dms, devicefarm, directconnect,
189 ds, dynamodb, ec2, ecr, ecs, ssm, elasticbeanstalk, elasticfilesystem,
190 elasticloadbalancing, elasticmapreduce, elastictranscoder, elasticache,
191 es, gamelift, glacier, health, iam, importexport, inspector, iot,
192 kms, kinesisanalytics, firehose, kinesis, lambda, lightsail,
193 machinelearning, aws_marketplace, aws_marketplace_management,
194 mobileanalytics, mobilehub, opsworks, opsworks_cm, polly,
195 redshift, rds, route53, route53domains, sts, servicecatalog,
196 ses, sns, sqs, s3, swf, sdb, states, storagegateway, support,
197 trustedadvisor, waf, workmail, workspaces, wildcard
204 // Once we refity tenant, we should probably use that instead of a
207 std::string resource;
210 : partition(Partition::wildcard), service(Service::wildcard) {}
211 ARN(Partition partition, Service service, std::string region,
212 std::string account, std::string resource)
213 : partition(partition), service(service), region(std::move(region)),
214 account(std::move(account)), resource(std::move(resource)) {}
215 ARN(const rgw_obj& o);
216 ARN(const rgw_bucket& b);
217 ARN(const rgw_bucket& b, const std::string& o);
219 static boost::optional<ARN> parse(const std::string& s,
220 bool wildcard = false);
221 std::string to_string() const;
223 // `this` is the pattern
224 bool match(const ARN& candidate) const;
227 inline std::string to_string(const ARN& a) {
228 return a.to_string();
231 inline std::ostream& operator <<(std::ostream& m, const ARN& a) {
232 return m << to_string(a);
235 bool operator ==(const ARN& l, const ARN& r);
236 bool operator <(const ARN& l, const ARN& r);
238 using Address = std::bitset<128>;
242 // Since we're mapping IPv6 to IPv4 addresses, we may want to
243 // consider making the prefix always be in terms of a v6 address
244 // and just use the v6 bit to rewrite it as a v4 prefix for
249 std::ostream& operator <<(std::ostream& m, const MaskedIP& ip);
250 string to_string(const MaskedIP& m);
252 inline bool operator ==(const MaskedIP& l, const MaskedIP& r) {
253 auto shift = std::max((l.v6 ? 128 : 32) - l.prefix,
254 (r.v6 ? 128 : 32) - r.prefix);
255 return (l.addr >> shift) == (r.addr >> shift);
260 // Originally I was going to use a perfect hash table, but Marcus
261 // says keys are to be added at run-time not compile time.
263 // In future development, use symbol internment.
265 bool ifexists = false;
266 // Much to my annoyance there is no actual way to do this in a
267 // typed way that is compatible with AWS. I know this because I've
268 // seen examples where the same value is used as a string in one
269 // context and a date in another.
270 std::vector<std::string> vals;
272 Condition() = default;
273 Condition(TokenID op, const char* s, std::size_t len, bool ifexists)
274 : op(op), key(s, len), ifexists(ifexists) {}
276 bool eval(const Environment& e) const;
278 static boost::optional<double> as_number(const std::string& s) {
282 double d = std::stod(s, &p);
283 if (p < s.length()) {
288 } catch (const std::logic_error& e) {
293 static boost::optional<ceph::real_time> as_date(const std::string& s) {
297 double d = std::stod(s, &p);
298 if (p == s.length()) {
299 return ceph::real_time(
300 std::chrono::seconds(static_cast<uint64_t>(d)) +
301 std::chrono::nanoseconds(
302 static_cast<uint64_t>((d - static_cast<uint64_t>(d))
306 return from_iso_8601(boost::string_ref(s), false);
307 } catch (const std::logic_error& e) {
312 static boost::optional<bool> as_bool(const std::string& s) {
315 if (s.empty() || boost::iequals(s, "false")) {
320 double d = std::stod(s, &p);
321 if (p == s.length()) {
322 return !((d == +0.0) || (d == -0.0) || std::isnan(d));
324 } catch (const std::logic_error& e) {
331 static boost::optional<ceph::bufferlist> as_binary(const std::string& s) {
333 ceph::bufferlist base64;
334 // I could populate a bufferlist
335 base64.push_back(buffer::create_static(
337 const_cast<char*>(s.data()))); // Yuck
338 // From a base64 encoded std::string.
339 ceph::bufferlist bin;
342 base64.decode_base64(bin);
343 } catch (const ceph::buffer::malformed_input& e) {
349 static boost::optional<MaskedIP> as_network(const std::string& s);
353 bool operator ()(const std::string& s1,
354 const std::string& s2) const {
355 return boost::iequals(s1, s2);
360 bool operator ()(const std::string& input,
361 const std::string& pattern) const {
362 return match_wildcards(pattern, input, 0);
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));