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