]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_iam_policy.h
import ceph 16.2.6
[ceph.git] / ceph / src / rgw / rgw_iam_policy.h
CommitLineData
31f18b77 1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
9f95a23c 2// vim: ts=8 sw=2 smarttab ft=cpp
31f18b77
FG
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>
f67539c2 12#include <string_view>
31f18b77
FG
13
14#include <boost/algorithm/string/predicate.hpp>
15#include <boost/container/flat_map.hpp>
16#include <boost/container/flat_set.hpp>
17#include <boost/optional.hpp>
18#include <boost/thread/shared_mutex.hpp>
31f18b77
FG
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
c07f9fc5 27#include "rgw_acl.h"
31f18b77
FG
28#include "rgw_basic_types.h"
29#include "rgw_iam_policy_keywords.h"
d2e6a577 30#include "rgw_string.h"
eafe8130 31#include "rgw_arn.h"
31f18b77 32
31f18b77
FG
33namespace rgw {
34namespace auth {
35class Identity;
36}
37}
31f18b77
FG
38
39namespace rgw {
40namespace IAM {
11fdf7f2
TL
41
42static constexpr std::uint64_t s3GetObject = 0;
43static constexpr std::uint64_t s3GetObjectVersion = 1;
44static constexpr std::uint64_t s3PutObject = 2;
45static constexpr std::uint64_t s3GetObjectAcl = 3;
46static constexpr std::uint64_t s3GetObjectVersionAcl = 4;
47static constexpr std::uint64_t s3PutObjectAcl = 5;
48static constexpr std::uint64_t s3PutObjectVersionAcl = 6;
49static constexpr std::uint64_t s3DeleteObject = 7;
50static constexpr std::uint64_t s3DeleteObjectVersion = 8;
51static constexpr std::uint64_t s3ListMultipartUploadParts = 9;
52static constexpr std::uint64_t s3AbortMultipartUpload = 10;
53static constexpr std::uint64_t s3GetObjectTorrent = 11;
54static constexpr std::uint64_t s3GetObjectVersionTorrent = 12;
55static constexpr std::uint64_t s3RestoreObject = 13;
56static constexpr std::uint64_t s3CreateBucket = 14;
57static constexpr std::uint64_t s3DeleteBucket = 15;
58static constexpr std::uint64_t s3ListBucket = 16;
59static constexpr std::uint64_t s3ListBucketVersions = 17;
60static constexpr std::uint64_t s3ListAllMyBuckets = 18;
61static constexpr std::uint64_t s3ListBucketMultipartUploads = 19;
62static constexpr std::uint64_t s3GetAccelerateConfiguration = 20;
63static constexpr std::uint64_t s3PutAccelerateConfiguration = 21;
64static constexpr std::uint64_t s3GetBucketAcl = 22;
65static constexpr std::uint64_t s3PutBucketAcl = 23;
66static constexpr std::uint64_t s3GetBucketCORS = 24;
67static constexpr std::uint64_t s3PutBucketCORS = 25;
68static constexpr std::uint64_t s3GetBucketVersioning = 26;
69static constexpr std::uint64_t s3PutBucketVersioning = 27;
70static constexpr std::uint64_t s3GetBucketRequestPayment = 28;
71static constexpr std::uint64_t s3PutBucketRequestPayment = 29;
72static constexpr std::uint64_t s3GetBucketLocation = 30;
73static constexpr std::uint64_t s3GetBucketPolicy = 31;
74static constexpr std::uint64_t s3DeleteBucketPolicy = 32;
75static constexpr std::uint64_t s3PutBucketPolicy = 33;
76static constexpr std::uint64_t s3GetBucketNotification = 34;
77static constexpr std::uint64_t s3PutBucketNotification = 35;
78static constexpr std::uint64_t s3GetBucketLogging = 36;
79static constexpr std::uint64_t s3PutBucketLogging = 37;
80static constexpr std::uint64_t s3GetBucketTagging = 38;
81static constexpr std::uint64_t s3PutBucketTagging = 39;
82static constexpr std::uint64_t s3GetBucketWebsite = 40;
83static constexpr std::uint64_t s3PutBucketWebsite = 41;
84static constexpr std::uint64_t s3DeleteBucketWebsite = 42;
85static constexpr std::uint64_t s3GetLifecycleConfiguration = 43;
86static constexpr std::uint64_t s3PutLifecycleConfiguration = 44;
87static constexpr std::uint64_t s3PutReplicationConfiguration = 45;
88static constexpr std::uint64_t s3GetReplicationConfiguration = 46;
89static constexpr std::uint64_t s3DeleteReplicationConfiguration = 47;
90static constexpr std::uint64_t s3GetObjectTagging = 48;
91static constexpr std::uint64_t s3PutObjectTagging = 49;
92static constexpr std::uint64_t s3DeleteObjectTagging = 50;
93static constexpr std::uint64_t s3GetObjectVersionTagging = 51;
94static constexpr std::uint64_t s3PutObjectVersionTagging = 52;
95static constexpr std::uint64_t s3DeleteObjectVersionTagging = 53;
eafe8130
TL
96static constexpr std::uint64_t s3PutBucketObjectLockConfiguration = 54;
97static constexpr std::uint64_t s3GetBucketObjectLockConfiguration = 55;
98static constexpr std::uint64_t s3PutObjectRetention = 56;
99static constexpr std::uint64_t s3GetObjectRetention = 57;
100static constexpr std::uint64_t s3PutObjectLegalHold = 58;
101static constexpr std::uint64_t s3GetObjectLegalHold = 59;
102static constexpr std::uint64_t s3BypassGovernanceRetention = 60;
9f95a23c
TL
103static constexpr std::uint64_t s3GetBucketPolicyStatus = 61;
104static constexpr std::uint64_t s3PutPublicAccessBlock = 62;
105static constexpr std::uint64_t s3GetPublicAccessBlock = 63;
106static constexpr std::uint64_t s3DeletePublicAccessBlock = 64;
107static constexpr std::uint64_t s3GetBucketPublicAccessBlock = 65;
108static constexpr std::uint64_t s3PutBucketPublicAccessBlock = 66;
109static constexpr std::uint64_t s3DeleteBucketPublicAccessBlock = 67;
110static constexpr std::uint64_t s3All = 68;
111
112static constexpr std::uint64_t iamPutUserPolicy = s3All + 1;
113static constexpr std::uint64_t iamGetUserPolicy = s3All + 2;
114static constexpr std::uint64_t iamDeleteUserPolicy = s3All + 3;
115static constexpr std::uint64_t iamListUserPolicies = s3All + 4;
116static constexpr std::uint64_t iamCreateRole = s3All + 5;
117static constexpr std::uint64_t iamDeleteRole = s3All + 6;
118static constexpr std::uint64_t iamModifyRole = s3All + 7;
119static constexpr std::uint64_t iamGetRole = s3All + 8;
120static constexpr std::uint64_t iamListRoles = s3All + 9;
121static constexpr std::uint64_t iamPutRolePolicy = s3All + 10;
122static constexpr std::uint64_t iamGetRolePolicy = s3All + 11;
123static constexpr std::uint64_t iamListRolePolicies = s3All + 12;
124static constexpr std::uint64_t iamDeleteRolePolicy = s3All + 13;
f91f0fd5
TL
125static constexpr std::uint64_t iamCreateOIDCProvider = s3All + 14;
126static constexpr std::uint64_t iamDeleteOIDCProvider = s3All + 15;
127static constexpr std::uint64_t iamGetOIDCProvider = s3All + 16;
128static constexpr std::uint64_t iamListOIDCProviders = s3All + 17;
129static constexpr std::uint64_t iamAll = s3All + 18;
9f95a23c
TL
130
131static constexpr std::uint64_t stsAssumeRole = iamAll + 1;
132static constexpr std::uint64_t stsAssumeRoleWithWebIdentity = iamAll + 2;
133static constexpr std::uint64_t stsGetSessionToken = iamAll + 3;
134static constexpr std::uint64_t stsAll = iamAll + 4;
135
136static constexpr std::uint64_t s3Count = s3All;
11fdf7f2
TL
137static constexpr std::uint64_t allCount = stsAll + 1;
138
92f5a8d4 139using Action_t = std::bitset<allCount>;
11fdf7f2
TL
140using NotAction_t = Action_t;
141
9f95a23c
TL
142template <size_t N>
143constexpr std::bitset<N> make_bitmask(size_t s) {
144 // unfortunately none of the shift/logic operators of std::bitset have a constexpr variation
145 return s < 64 ? std::bitset<N> ((1ULL << s) - 1) :
146 std::bitset<N>((1ULL << 63) - 1) | make_bitmask<N> (s - 63) << 63;
147}
148
149template <size_t N>
150constexpr std::bitset<N> set_cont_bits(size_t start, size_t end)
151{
152 return (make_bitmask<N>(end - start)) << start;
153}
154
11fdf7f2 155static const Action_t None(0);
9f95a23c
TL
156static const Action_t s3AllValue = set_cont_bits<allCount>(0,s3All);
157static const Action_t iamAllValue = set_cont_bits<allCount>(s3All+1,iamAll);
158static const Action_t stsAllValue = set_cont_bits<allCount>(iamAll+1,stsAll);
159static const Action_t allValue = set_cont_bits<allCount>(0,allCount);
31f18b77
FG
160
161namespace {
a8e16298
TL
162// Please update the table in doc/radosgw/s3/authentication.rst if you
163// modify this function.
31f18b77
FG
164inline int op_to_perm(std::uint64_t op) {
165 switch (op) {
166 case s3GetObject:
167 case s3GetObjectTorrent:
168 case s3GetObjectVersion:
169 case s3GetObjectVersionTorrent:
224ce89b
WB
170 case s3GetObjectTagging:
171 case s3GetObjectVersionTagging:
eafe8130
TL
172 case s3GetObjectRetention:
173 case s3GetObjectLegalHold:
31f18b77
FG
174 case s3ListAllMyBuckets:
175 case s3ListBucket:
28e407b8 176 case s3ListBucketMultipartUploads:
31f18b77
FG
177 case s3ListBucketVersions:
178 case s3ListMultipartUploadParts:
179 return RGW_PERM_READ;
180
181 case s3AbortMultipartUpload:
182 case s3CreateBucket:
183 case s3DeleteBucket:
184 case s3DeleteObject:
185 case s3DeleteObjectVersion:
186 case s3PutObject:
224ce89b
WB
187 case s3PutObjectTagging:
188 case s3PutObjectVersionTagging:
189 case s3DeleteObjectTagging:
190 case s3DeleteObjectVersionTagging:
31f18b77 191 case s3RestoreObject:
eafe8130
TL
192 case s3PutObjectRetention:
193 case s3PutObjectLegalHold:
194 case s3BypassGovernanceRetention:
31f18b77
FG
195 return RGW_PERM_WRITE;
196
197 case s3GetAccelerateConfiguration:
198 case s3GetBucketAcl:
199 case s3GetBucketCORS:
200 case s3GetBucketLocation:
201 case s3GetBucketLogging:
202 case s3GetBucketNotification:
203 case s3GetBucketPolicy:
9f95a23c 204 case s3GetBucketPolicyStatus:
31f18b77
FG
205 case s3GetBucketRequestPayment:
206 case s3GetBucketTagging:
207 case s3GetBucketVersioning:
208 case s3GetBucketWebsite:
209 case s3GetLifecycleConfiguration:
210 case s3GetObjectAcl:
211 case s3GetObjectVersionAcl:
212 case s3GetReplicationConfiguration:
eafe8130 213 case s3GetBucketObjectLockConfiguration:
9f95a23c 214 case s3GetBucketPublicAccessBlock:
31f18b77
FG
215 return RGW_PERM_READ_ACP;
216
217 case s3DeleteBucketPolicy:
218 case s3DeleteBucketWebsite:
219 case s3DeleteReplicationConfiguration:
220 case s3PutAccelerateConfiguration:
221 case s3PutBucketAcl:
222 case s3PutBucketCORS:
223 case s3PutBucketLogging:
224 case s3PutBucketNotification:
225 case s3PutBucketPolicy:
226 case s3PutBucketRequestPayment:
227 case s3PutBucketTagging:
228 case s3PutBucketVersioning:
229 case s3PutBucketWebsite:
230 case s3PutLifecycleConfiguration:
231 case s3PutObjectAcl:
232 case s3PutObjectVersionAcl:
233 case s3PutReplicationConfiguration:
eafe8130 234 case s3PutBucketObjectLockConfiguration:
9f95a23c 235 case s3PutBucketPublicAccessBlock:
31f18b77
FG
236 return RGW_PERM_WRITE_ACP;
237
238 case s3All:
239 return RGW_PERM_FULL_CONTROL;
240 }
241 return RGW_PERM_INVALID;
242}
243}
244
522d829b
TL
245enum class PolicyPrincipal {
246 Role,
247 Session,
248 Other
249};
250
31f18b77
FG
251using Environment = boost::container::flat_map<std::string, std::string>;
252
31f18b77
FG
253using Address = std::bitset<128>;
254struct MaskedIP {
255 bool v6;
256 Address addr;
257 // Since we're mapping IPv6 to IPv4 addresses, we may want to
258 // consider making the prefix always be in terms of a v6 address
259 // and just use the v6 bit to rewrite it as a v4 prefix for
260 // output.
261 unsigned int prefix;
262};
263
264std::ostream& operator <<(std::ostream& m, const MaskedIP& ip);
31f18b77
FG
265
266inline bool operator ==(const MaskedIP& l, const MaskedIP& r) {
b32b8144
FG
267 auto shift = std::max((l.v6 ? 128 : 32) - ((int) l.prefix),
268 (r.v6 ? 128 : 32) - ((int) r.prefix));
269 ceph_assert(shift >= 0);
31f18b77
FG
270 return (l.addr >> shift) == (r.addr >> shift);
271}
272
273struct Condition {
274 TokenID op;
275 // Originally I was going to use a perfect hash table, but Marcus
276 // says keys are to be added at run-time not compile time.
277
278 // In future development, use symbol internment.
279 std::string key;
280 bool ifexists = false;
281 // Much to my annoyance there is no actual way to do this in a
282 // typed way that is compatible with AWS. I know this because I've
283 // seen examples where the same value is used as a string in one
284 // context and a date in another.
285 std::vector<std::string> vals;
286
287 Condition() = default;
c07f9fc5
FG
288 Condition(TokenID op, const char* s, std::size_t len, bool ifexists)
289 : op(op), key(s, len), ifexists(ifexists) {}
31f18b77
FG
290
291 bool eval(const Environment& e) const;
292
293 static boost::optional<double> as_number(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 boost::none;
300 }
301
302 return d;
303 } catch (const std::logic_error& e) {
304 return boost::none;
305 }
306 }
307
308 static boost::optional<ceph::real_time> as_date(const std::string& s) {
309 std::size_t p = 0;
310
311 try {
312 double d = std::stod(s, &p);
313 if (p == s.length()) {
314 return ceph::real_time(
315 std::chrono::seconds(static_cast<uint64_t>(d)) +
316 std::chrono::nanoseconds(
317 static_cast<uint64_t>((d - static_cast<uint64_t>(d))
318 * 1000000000)));
319 }
320
f67539c2 321 return from_iso_8601(std::string_view(s), false);
31f18b77
FG
322 } catch (const std::logic_error& e) {
323 return boost::none;
324 }
325 }
326
327 static boost::optional<bool> as_bool(const std::string& s) {
328 std::size_t p = 0;
329
330 if (s.empty() || boost::iequals(s, "false")) {
331 return false;
332 }
333
334 try {
335 double d = std::stod(s, &p);
336 if (p == s.length()) {
c07f9fc5 337 return !((d == +0.0) || (d == -0.0) || std::isnan(d));
31f18b77
FG
338 }
339 } catch (const std::logic_error& e) {
340 // Fallthrough
341 }
342
343 return true;
344 }
345
346 static boost::optional<ceph::bufferlist> as_binary(const std::string& s) {
347 // In a just world
348 ceph::bufferlist base64;
349 // I could populate a bufferlist
350 base64.push_back(buffer::create_static(
351 s.length(),
352 const_cast<char*>(s.data()))); // Yuck
353 // From a base64 encoded std::string.
354 ceph::bufferlist bin;
355
356 try {
92f5a8d4 357 bin.decode_base64(base64);
31f18b77
FG
358 } catch (const ceph::buffer::malformed_input& e) {
359 return boost::none;
360 }
361 return bin;
362 }
363
364 static boost::optional<MaskedIP> as_network(const std::string& s);
365
366
d2e6a577 367 struct ci_equal_to {
31f18b77
FG
368 bool operator ()(const std::string& s1,
369 const std::string& s2) const {
370 return boost::iequals(s1, s2);
371 }
372 };
373
d2e6a577
FG
374 struct string_like {
375 bool operator ()(const std::string& input,
376 const std::string& pattern) const {
377 return match_wildcards(pattern, input, 0);
378 }
379 };
31f18b77 380
11fdf7f2
TL
381 struct ci_starts_with {
382 bool operator()(const std::string& s1,
383 const std::string& s2) const {
384 return boost::istarts_with(s1, s2);
385 }
386 };
387
31f18b77
FG
388 template<typename F>
389 static bool orrible(F&& f, const std::string& c,
390 const std::vector<std::string>& v) {
391 for (const auto& d : v) {
392 if (std::forward<F>(f)(c, d)) {
393 return true;
394 }
395 }
396 return false;
397 }
398
399 template<typename F, typename X>
400 static bool shortible(F&& f, X& x, const std::string& c,
401 const std::vector<std::string>& v) {
402 auto xc = std::forward<X>(x)(c);
403 if (!xc) {
404 return false;
405 }
406
407 for (const auto& d : v) {
408 auto xd = std::forward<X>(x)(d);
409 if (!xd) {
410 continue;
411 }
412
413 if (std::forward<F>(f)(*xc, *xd)) {
414 return true;
415 }
416 }
417 return false;
418 }
11fdf7f2
TL
419
420 template <typename F>
421 bool has_key_p(const std::string& _key, F p) const {
422 return p(key, _key);
423 }
31f18b77
FG
424};
425
426std::ostream& operator <<(std::ostream& m, const Condition& c);
427
31f18b77
FG
428struct Statement {
429 boost::optional<std::string> sid = boost::none;
430
431 boost::container::flat_set<rgw::auth::Principal> princ;
432 boost::container::flat_set<rgw::auth::Principal> noprinc;
433
434 // Every statement MUST provide an effect. I just initialize it to
435 // deny as defensive programming.
436 Effect effect = Effect::Deny;
437
11fdf7f2
TL
438 Action_t action = 0;
439 NotAction_t notaction = 0;
31f18b77
FG
440
441 boost::container::flat_set<ARN> resource;
442 boost::container::flat_set<ARN> notresource;
443
444 std::vector<Condition> conditions;
445
446 Effect eval(const Environment& e,
447 boost::optional<const rgw::auth::Identity&> ida,
522d829b 448 std::uint64_t action, const ARN& resource, boost::optional<PolicyPrincipal&> princ_type=boost::none) const;
11fdf7f2
TL
449
450 Effect eval_principal(const Environment& e,
522d829b 451 boost::optional<const rgw::auth::Identity&> ida, boost::optional<PolicyPrincipal&> princ_type=boost::none) const;
11fdf7f2
TL
452
453 Effect eval_conditions(const Environment& e) const;
31f18b77
FG
454};
455
456std::ostream& operator <<(ostream& m, const Statement& s);
31f18b77
FG
457
458struct PolicyParseException : public std::exception {
459 rapidjson::ParseResult pr;
460
11fdf7f2 461 explicit PolicyParseException(rapidjson::ParseResult&& pr)
31f18b77
FG
462 : pr(pr) { }
463 const char* what() const noexcept override {
464 return rapidjson::GetParseError_En(pr.Code());
465 }
466};
467
468struct Policy {
469 std::string text;
470 Version version = Version::v2008_10_17;
471 boost::optional<std::string> id = boost::none;
472
473 std::vector<Statement> statements;
474
475 Policy(CephContext* cct, const std::string& tenant,
476 const bufferlist& text);
477
478 Effect eval(const Environment& e,
479 boost::optional<const rgw::auth::Identity&> ida,
522d829b 480 std::uint64_t action, const ARN& resource, boost::optional<PolicyPrincipal&> princ_type=boost::none) const;
11fdf7f2
TL
481
482 Effect eval_principal(const Environment& e,
522d829b 483 boost::optional<const rgw::auth::Identity&> ida, boost::optional<PolicyPrincipal&> princ_type=boost::none) const;
11fdf7f2
TL
484
485 Effect eval_conditions(const Environment& e) const;
486
487 template <typename F>
488 bool has_conditional(const string& conditional, F p) const {
489 for (const auto&s: statements){
490 if (std::any_of(s.conditions.begin(), s.conditions.end(),
491 [&](const Condition& c) { return c.has_key_p(conditional, p);}))
492 return true;
493 }
494 return false;
495 }
496
497 bool has_conditional(const string& c) const {
498 return has_conditional(c, Condition::ci_equal_to());
499 }
500
501 bool has_partial_conditional(const string& c) const {
502 return has_conditional(c, Condition::ci_starts_with());
503 }
31f18b77
FG
504};
505
506std::ostream& operator <<(ostream& m, const Policy& p);
9f95a23c
TL
507bool is_public(const Policy& p);
508
31f18b77
FG
509}
510}
511
31f18b77 512#endif