Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / rgw / rgw_iam_policy.h
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #ifndef CEPH_RGW_IAM_POLICY_H
5 #define CEPH_RGW_IAM_POLICY_H
6
7 #include <bitset>
8 #include <chrono>
9 #include <cstdint>
10 #include <iostream>
11 #include <string>
12
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>
20
21 #include "common/ceph_time.h"
22 #include "common/iso_8601.h"
23
24 #include "rapidjson/error/error.h"
25 #include "rapidjson/error/en.h"
26
27 #include "rgw_acl.h"
28 #include "rgw_basic_types.h"
29 #include "rgw_iam_policy_keywords.h"
30 #include "rgw_string.h"
31
32 class RGWRados;
33 namespace rgw {
34 namespace auth {
35 class Identity;
36 }
37 }
38 struct rgw_obj;
39 struct rgw_bucket;
40
41 namespace rgw {
42 namespace IAM {
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;
100
101 namespace {
102 inline int op_to_perm(std::uint64_t op) {
103   switch (op) {
104   case s3GetObject:
105   case s3GetObjectTorrent:
106   case s3GetObjectVersion:
107   case s3GetObjectVersionTorrent:
108   case s3GetObjectTagging:
109   case s3GetObjectVersionTagging:
110   case s3ListAllMyBuckets:
111   case s3ListBucket:
112   case s3ListBucketMultiPartUploads:
113   case s3ListBucketVersions:
114   case s3ListMultipartUploadParts:
115     return RGW_PERM_READ;
116
117   case s3AbortMultipartUpload:
118   case s3CreateBucket:
119   case s3DeleteBucket:
120   case s3DeleteObject:
121   case s3DeleteObjectVersion:
122   case s3PutObject:
123   case s3PutObjectTagging:
124   case s3PutObjectVersionTagging:
125   case s3DeleteObjectTagging:
126   case s3DeleteObjectVersionTagging:
127   case s3RestoreObject:
128     return RGW_PERM_WRITE;
129
130   case s3GetAccelerateConfiguration:
131   case s3GetBucketAcl:
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:
142   case s3GetObjectAcl:
143   case s3GetObjectVersionAcl:
144   case s3GetReplicationConfiguration:
145     return RGW_PERM_READ_ACP;
146
147   case s3DeleteBucketPolicy:
148   case s3DeleteBucketWebsite:
149   case s3DeleteReplicationConfiguration:
150   case s3PutAccelerateConfiguration:
151   case s3PutBucketAcl:
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:
161   case s3PutObjectAcl:
162   case s3PutObjectVersionAcl:
163   case s3PutReplicationConfiguration:
164     return RGW_PERM_WRITE_ACP;
165
166   case s3All:
167     return RGW_PERM_FULL_CONTROL;
168   }
169   return RGW_PERM_INVALID;
170 }
171 }
172
173 using Environment = boost::container::flat_map<std::string, std::string>;
174
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'
180   // partition type.
181 };
182
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
198 };
199
200 struct ARN {
201   Partition partition;
202   Service service;
203   std::string region;
204   // Once we refity tenant, we should probably use that instead of a
205   // string.
206   std::string account;
207   std::string resource;
208
209   ARN()
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);
218
219   static boost::optional<ARN> parse(const std::string& s,
220                                     bool wildcard = false);
221   std::string to_string() const;
222
223   // `this` is the pattern
224   bool match(const ARN& candidate) const;
225 };
226
227 inline std::string to_string(const ARN& a) {
228   return a.to_string();
229 }
230
231 inline std::ostream& operator <<(std::ostream& m, const ARN& a) {
232   return m << to_string(a);
233 }
234
235 bool operator ==(const ARN& l, const ARN& r);
236 bool operator <(const ARN& l, const ARN& r);
237
238 using Address = std::bitset<128>;
239 struct MaskedIP {
240   bool v6;
241   Address addr;
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
245   // output.
246   unsigned int prefix;
247 };
248
249 std::ostream& operator <<(std::ostream& m, const MaskedIP& ip);
250 string to_string(const MaskedIP& m);
251
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);
256 }
257
258 struct Condition {
259   TokenID op;
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.
262
263   // In future development, use symbol internment.
264   std::string key;
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;
271
272   Condition() = default;
273   Condition(TokenID op, const char* s, std::size_t len, bool ifexists)
274     : op(op), key(s, len), ifexists(ifexists) {}
275
276   bool eval(const Environment& e) const;
277
278   static boost::optional<double> as_number(const std::string& s) {
279     std::size_t p = 0;
280
281     try {
282       double d = std::stod(s, &p);
283       if (p < s.length()) {
284         return boost::none;
285       }
286
287       return d;
288     } catch (const std::logic_error& e) {
289       return boost::none;
290     }
291   }
292
293   static boost::optional<ceph::real_time> as_date(const std::string& s) {
294     std::size_t p = 0;
295
296     try {
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))
303                                   * 1000000000)));
304       }
305
306       return from_iso_8601(boost::string_ref(s), false);
307     } catch (const std::logic_error& e) {
308       return boost::none;
309     }
310   }
311
312   static boost::optional<bool> as_bool(const std::string& s) {
313     std::size_t p = 0;
314
315     if (s.empty() || boost::iequals(s, "false")) {
316       return false;
317     }
318
319     try {
320       double d = std::stod(s, &p);
321       if (p == s.length()) {
322         return !((d == +0.0) || (d == -0.0) || std::isnan(d));
323       }
324     } catch (const std::logic_error& e) {
325       // Fallthrough
326     }
327
328     return true;
329   }
330
331   static boost::optional<ceph::bufferlist> as_binary(const std::string& s) {
332     // In a just world
333     ceph::bufferlist base64;
334     // I could populate a bufferlist
335     base64.push_back(buffer::create_static(
336                        s.length(),
337                        const_cast<char*>(s.data()))); // Yuck
338     // From a base64 encoded std::string.
339     ceph::bufferlist bin;
340
341     try {
342       base64.decode_base64(bin);
343     } catch (const ceph::buffer::malformed_input& e) {
344       return boost::none;
345     }
346     return bin;
347   }
348
349   static boost::optional<MaskedIP> as_network(const std::string& s);
350
351
352   struct ci_equal_to {
353     bool operator ()(const std::string& s1,
354                      const std::string& s2) const {
355       return boost::iequals(s1, s2);
356     }
357   };
358
359   struct string_like {
360     bool operator ()(const std::string& input,
361                      const std::string& pattern) const {
362       return match_wildcards(pattern, input, 0);
363     }
364   };
365
366   template<typename F>
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)) {
371         return true;
372       }
373     }
374     return false;
375   }
376
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);
381     if (!xc) {
382       return false;
383     }
384
385     for (const auto& d : v) {
386       auto xd = std::forward<X>(x)(d);
387       if (!xd) {
388         continue;
389       }
390
391       if (std::forward<F>(f)(*xc, *xd)) {
392         return true;
393       }
394     }
395     return false;
396   }
397 };
398
399 std::ostream& operator <<(std::ostream& m, const Condition& c);
400
401 std::string to_string(const Condition& c);
402
403 struct Statement {
404   boost::optional<std::string> sid = boost::none;
405
406   boost::container::flat_set<rgw::auth::Principal> princ;
407   boost::container::flat_set<rgw::auth::Principal> noprinc;
408
409   // Every statement MUST provide an effect. I just initialize it to
410   // deny as defensive programming.
411   Effect effect = Effect::Deny;
412
413   std::uint64_t action = 0;
414   std::uint64_t notaction = 0;
415
416   boost::container::flat_set<ARN> resource;
417   boost::container::flat_set<ARN> notresource;
418
419   std::vector<Condition> conditions;
420
421   Effect eval(const Environment& e,
422               boost::optional<const rgw::auth::Identity&> ida,
423               std::uint64_t action, const ARN& resource) const;
424 };
425
426 std::ostream& operator <<(ostream& m, const Statement& s);
427 std::string to_string(const Statement& s);
428
429 struct PolicyParseException : public std::exception {
430   rapidjson::ParseResult pr;
431
432   PolicyParseException(rapidjson::ParseResult&& pr)
433     : pr(pr) { }
434   const char* what() const noexcept override {
435     return rapidjson::GetParseError_En(pr.Code());
436   }
437 };
438
439 struct Policy {
440   std::string text;
441   Version version = Version::v2008_10_17;
442   boost::optional<std::string> id = boost::none;
443
444   std::vector<Statement> statements;
445
446   Policy(CephContext* cct, const std::string& tenant,
447          const bufferlist& text);
448
449   Effect eval(const Environment& e,
450               boost::optional<const rgw::auth::Identity&> ida,
451               std::uint64_t action, const ARN& resource) const;
452 };
453
454 std::ostream& operator <<(ostream& m, const Policy& p);
455 std::string to_string(const Policy& p);
456 }
457 }
458
459 namespace std {
460 template<>
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));
465   }
466 };
467 }
468
469 #endif