]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_acl.h
import ceph pacific 16.2.5
[ceph.git] / ceph / src / rgw / rgw_acl.h
CommitLineData
7c673cae 1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
9f95a23c 2// vim: ts=8 sw=2 smarttab ft=cpp
7c673cae
FG
3
4#ifndef CEPH_RGW_ACL_H
5#define CEPH_RGW_ACL_H
6
7#include <map>
8#include <string>
f67539c2 9#include <string_view>
7c673cae
FG
10#include <include/types.h>
11
12#include <boost/optional.hpp>
f67539c2 13#include <boost/algorithm/string/predicate.hpp>
7c673cae
FG
14
15#include "common/debug.h"
16
17#include "rgw_basic_types.h"
18
7c673cae
FG
19#define RGW_PERM_NONE 0x00
20#define RGW_PERM_READ 0x01
21#define RGW_PERM_WRITE 0x02
22#define RGW_PERM_READ_ACP 0x04
23#define RGW_PERM_WRITE_ACP 0x08
24#define RGW_PERM_READ_OBJS 0x10
25#define RGW_PERM_WRITE_OBJS 0x20
26#define RGW_PERM_FULL_CONTROL ( RGW_PERM_READ | RGW_PERM_WRITE | \
27 RGW_PERM_READ_ACP | RGW_PERM_WRITE_ACP )
28#define RGW_PERM_ALL_S3 RGW_PERM_FULL_CONTROL
29#define RGW_PERM_INVALID 0xFF00
30
31f18b77
FG
31static constexpr char RGW_REFERER_WILDCARD[] = "*";
32
7c673cae
FG
33enum ACLGranteeTypeEnum {
34/* numbers are encoded, should not change */
35 ACL_TYPE_CANON_USER = 0,
36 ACL_TYPE_EMAIL_USER = 1,
37 ACL_TYPE_GROUP = 2,
38 ACL_TYPE_UNKNOWN = 3,
39 ACL_TYPE_REFERER = 4,
40};
41
42enum ACLGroupTypeEnum {
43/* numbers are encoded should not change */
44 ACL_GROUP_NONE = 0,
45 ACL_GROUP_ALL_USERS = 1,
46 ACL_GROUP_AUTHENTICATED_USERS = 2,
47};
48
49class ACLPermission
50{
51protected:
52 int flags;
53public:
54 ACLPermission() : flags(0) {}
55 ~ACLPermission() {}
56 uint32_t get_permissions() const { return flags; }
57 void set_permissions(uint32_t perm) { flags = perm; }
58
59 void encode(bufferlist& bl) const {
60 ENCODE_START(2, 2, bl);
11fdf7f2 61 encode(flags, bl);
7c673cae
FG
62 ENCODE_FINISH(bl);
63 }
11fdf7f2 64 void decode(bufferlist::const_iterator& bl) {
7c673cae 65 DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl);
11fdf7f2 66 decode(flags, bl);
7c673cae
FG
67 DECODE_FINISH(bl);
68 }
69 void dump(Formatter *f) const;
70 static void generate_test_instances(list<ACLPermission*>& o);
f67539c2
TL
71
72 friend bool operator==(const ACLPermission& lhs, const ACLPermission& rhs);
73 friend bool operator!=(const ACLPermission& lhs, const ACLPermission& rhs);
7c673cae
FG
74};
75WRITE_CLASS_ENCODER(ACLPermission)
76
77class ACLGranteeType
78{
79protected:
80 __u32 type;
81public:
82 ACLGranteeType() : type(ACL_TYPE_UNKNOWN) {}
83 virtual ~ACLGranteeType() {}
84// virtual const char *to_string() = 0;
85 ACLGranteeTypeEnum get_type() const { return (ACLGranteeTypeEnum)type; }
86 void set(ACLGranteeTypeEnum t) { type = t; }
87// virtual void set(const char *s) = 0;
88 void encode(bufferlist& bl) const {
89 ENCODE_START(2, 2, bl);
11fdf7f2 90 encode(type, bl);
7c673cae
FG
91 ENCODE_FINISH(bl);
92 }
11fdf7f2 93 void decode(bufferlist::const_iterator& bl) {
7c673cae 94 DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl);
11fdf7f2 95 decode(type, bl);
7c673cae
FG
96 DECODE_FINISH(bl);
97 }
98 void dump(Formatter *f) const;
99 static void generate_test_instances(list<ACLGranteeType*>& o);
f67539c2
TL
100
101 friend bool operator==(const ACLGranteeType& lhs, const ACLGranteeType& rhs);
102 friend bool operator!=(const ACLGranteeType& lhs, const ACLGranteeType& rhs);
7c673cae
FG
103};
104WRITE_CLASS_ENCODER(ACLGranteeType)
105
106class ACLGrantee
107{
108public:
109 ACLGrantee() {}
110 ~ACLGrantee() {}
111};
112
113
114class ACLGrant
115{
116protected:
117 ACLGranteeType type;
118 rgw_user id;
119 string email;
f67539c2 120 mutable rgw_user email_id;
7c673cae
FG
121 ACLPermission permission;
122 string name;
123 ACLGroupTypeEnum group;
124 string url_spec;
125
126public:
127 ACLGrant() : group(ACL_GROUP_NONE) {}
128 virtual ~ACLGrant() {}
129
130 /* there's an assumption here that email/uri/id encodings are
131 different and there can't be any overlap */
132 bool get_id(rgw_user& _id) const {
133 switch(type.get_type()) {
134 case ACL_TYPE_EMAIL_USER:
135 _id = email; // implies from_str() that parses the 't:u' syntax
136 return true;
137 case ACL_TYPE_GROUP:
138 case ACL_TYPE_REFERER:
139 return false;
140 default:
141 _id = id;
142 return true;
143 }
144 }
f67539c2
TL
145
146 const rgw_user* get_id() const {
147 switch(type.get_type()) {
148 case ACL_TYPE_EMAIL_USER:
149 email_id.from_str(email);
150 return &email_id;
151 case ACL_TYPE_GROUP:
152 case ACL_TYPE_REFERER:
153 return nullptr;
154 default:
155 return &id;
156 }
157 }
158
7c673cae
FG
159 ACLGranteeType& get_type() { return type; }
160 const ACLGranteeType& get_type() const { return type; }
161 ACLPermission& get_permission() { return permission; }
162 const ACLPermission& get_permission() const { return permission; }
163 ACLGroupTypeEnum get_group() const { return group; }
164 const string& get_referer() const { return url_spec; }
165
166 void encode(bufferlist& bl) const {
167 ENCODE_START(5, 3, bl);
11fdf7f2 168 encode(type, bl);
7c673cae
FG
169 string s;
170 id.to_str(s);
11fdf7f2 171 encode(s, bl);
7c673cae 172 string uri;
11fdf7f2
TL
173 encode(uri, bl);
174 encode(email, bl);
175 encode(permission, bl);
176 encode(name, bl);
7c673cae 177 __u32 g = (__u32)group;
11fdf7f2
TL
178 encode(g, bl);
179 encode(url_spec, bl);
7c673cae
FG
180 ENCODE_FINISH(bl);
181 }
11fdf7f2 182 void decode(bufferlist::const_iterator& bl) {
7c673cae 183 DECODE_START_LEGACY_COMPAT_LEN(5, 3, 3, bl);
11fdf7f2 184 decode(type, bl);
7c673cae 185 string s;
11fdf7f2 186 decode(s, bl);
7c673cae
FG
187 id.from_str(s);
188 string uri;
11fdf7f2
TL
189 decode(uri, bl);
190 decode(email, bl);
191 decode(permission, bl);
192 decode(name, bl);
7c673cae
FG
193 if (struct_v > 1) {
194 __u32 g;
11fdf7f2 195 decode(g, bl);
7c673cae
FG
196 group = (ACLGroupTypeEnum)g;
197 } else {
198 group = uri_to_group(uri);
199 }
200 if (struct_v >= 5) {
11fdf7f2 201 decode(url_spec, bl);
7c673cae
FG
202 } else {
203 url_spec.clear();
204 }
205 DECODE_FINISH(bl);
206 }
207 void dump(Formatter *f) const;
208 static void generate_test_instances(list<ACLGrant*>& o);
209
210 ACLGroupTypeEnum uri_to_group(string& uri);
f67539c2 211
7c673cae
FG
212 void set_canon(const rgw_user& _id, const string& _name, const uint32_t perm) {
213 type.set(ACL_TYPE_CANON_USER);
214 id = _id;
215 name = _name;
216 permission.set_permissions(perm);
217 }
218 void set_group(ACLGroupTypeEnum _group, const uint32_t perm) {
219 type.set(ACL_TYPE_GROUP);
220 group = _group;
221 permission.set_permissions(perm);
222 }
223 void set_referer(const std::string& _url_spec, const uint32_t perm) {
224 type.set(ACL_TYPE_REFERER);
225 url_spec = _url_spec;
226 permission.set_permissions(perm);
227 }
f67539c2
TL
228
229 friend bool operator==(const ACLGrant& lhs, const ACLGrant& rhs);
230 friend bool operator!=(const ACLGrant& lhs, const ACLGrant& rhs);
7c673cae
FG
231};
232WRITE_CLASS_ENCODER(ACLGrant)
233
234struct ACLReferer {
235 std::string url_spec;
236 uint32_t perm;
237
238 ACLReferer() : perm(0) {}
239 ACLReferer(const std::string& url_spec,
240 const uint32_t perm)
241 : url_spec(url_spec),
242 perm(perm) {
243 }
244
f67539c2 245 bool is_match(std::string_view http_referer) const {
7c673cae
FG
246 const auto http_host = get_http_host(http_referer);
247 if (!http_host || http_host->length() < url_spec.length()) {
248 return false;
249 }
250
31f18b77
FG
251 if ("*" == url_spec) {
252 return true;
253 }
254
7c673cae
FG
255 if (http_host->compare(url_spec) == 0) {
256 return true;
257 }
258
259 if ('.' == url_spec[0]) {
260 /* Wildcard support: a referer matches the spec when its last char are
261 * perfectly equal to spec. */
f67539c2 262 return boost::algorithm::ends_with(http_host.value(), url_spec);
7c673cae
FG
263 }
264
265 return false;
266 }
267
268 void encode(bufferlist& bl) const {
269 ENCODE_START(1, 1, bl);
11fdf7f2
TL
270 encode(url_spec, bl);
271 encode(perm, bl);
7c673cae
FG
272 ENCODE_FINISH(bl);
273 }
11fdf7f2 274 void decode(bufferlist::const_iterator& bl) {
7c673cae 275 DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, bl);
11fdf7f2
TL
276 decode(url_spec, bl);
277 decode(perm, bl);
7c673cae
FG
278 DECODE_FINISH(bl);
279 }
280 void dump(Formatter *f) const;
281
f67539c2
TL
282 friend bool operator==(const ACLReferer& lhs, const ACLReferer& rhs);
283 friend bool operator!=(const ACLReferer& lhs, const ACLReferer& rhs);
284
7c673cae 285private:
f67539c2 286 boost::optional<std::string_view> get_http_host(const std::string_view url) const {
7c673cae 287 size_t pos = url.find("://");
f67539c2
TL
288 if (pos == std::string_view::npos || boost::algorithm::starts_with(url, "://") ||
289 boost::algorithm::ends_with(url, "://") || boost::algorithm::ends_with(url, "@")) {
7c673cae
FG
290 return boost::none;
291 }
f67539c2 292 std::string_view url_sub = url.substr(pos + strlen("://"));
7c673cae 293 pos = url_sub.find('@');
f67539c2 294 if (pos != std::string_view::npos) {
7c673cae
FG
295 url_sub = url_sub.substr(pos + 1);
296 }
297 pos = url_sub.find_first_of("/:");
f67539c2 298 if (pos == std::string_view::npos) {
7c673cae
FG
299 /* no port or path exists */
300 return url_sub;
301 }
302 return url_sub.substr(0, pos);
303 }
304};
305WRITE_CLASS_ENCODER(ACLReferer)
306
307namespace rgw {
308namespace auth {
309 class Identity;
310}
311}
312
f67539c2
TL
313using ACLGrantMap = std::multimap<std::string, ACLGrant>;
314
7c673cae
FG
315class RGWAccessControlList
316{
317protected:
318 CephContext *cct;
319 /* FIXME: in the feature we should consider switching to uint32_t also
320 * in data structures. */
321 map<string, int> acl_user_map;
322 map<uint32_t, int> acl_group_map;
323 list<ACLReferer> referer_list;
f67539c2 324 ACLGrantMap grant_map;
7c673cae
FG
325 void _add_grant(ACLGrant *grant);
326public:
327 explicit RGWAccessControlList(CephContext *_cct) : cct(_cct) {}
328 RGWAccessControlList() : cct(NULL) {}
329
330 void set_ctx(CephContext *ctx) {
331 cct = ctx;
332 }
333
334 virtual ~RGWAccessControlList() {}
335
11fdf7f2
TL
336 uint32_t get_perm(const DoutPrefixProvider* dpp,
337 const rgw::auth::Identity& auth_identity,
7c673cae 338 uint32_t perm_mask);
b3b6e05e 339 uint32_t get_group_perm(const DoutPrefixProvider *dpp, ACLGroupTypeEnum group, uint32_t perm_mask) const;
31f18b77
FG
340 uint32_t get_referer_perm(uint32_t current_perm,
341 std::string http_referer,
342 uint32_t perm_mask);
7c673cae
FG
343 void encode(bufferlist& bl) const {
344 ENCODE_START(4, 3, bl);
345 bool maps_initialized = true;
11fdf7f2
TL
346 encode(maps_initialized, bl);
347 encode(acl_user_map, bl);
348 encode(grant_map, bl);
349 encode(acl_group_map, bl);
350 encode(referer_list, bl);
7c673cae
FG
351 ENCODE_FINISH(bl);
352 }
11fdf7f2 353 void decode(bufferlist::const_iterator& bl) {
7c673cae
FG
354 DECODE_START_LEGACY_COMPAT_LEN(4, 3, 3, bl);
355 bool maps_initialized;
11fdf7f2
TL
356 decode(maps_initialized, bl);
357 decode(acl_user_map, bl);
358 decode(grant_map, bl);
7c673cae 359 if (struct_v >= 2) {
11fdf7f2 360 decode(acl_group_map, bl);
7c673cae 361 } else if (!maps_initialized) {
f67539c2 362 ACLGrantMap::iterator iter;
7c673cae
FG
363 for (iter = grant_map.begin(); iter != grant_map.end(); ++iter) {
364 ACLGrant& grant = iter->second;
365 _add_grant(&grant);
366 }
367 }
368 if (struct_v >= 4) {
11fdf7f2 369 decode(referer_list, bl);
7c673cae
FG
370 }
371 DECODE_FINISH(bl);
372 }
373 void dump(Formatter *f) const;
374 static void generate_test_instances(list<RGWAccessControlList*>& o);
375
376 void add_grant(ACLGrant *grant);
9f95a23c 377 void remove_canon_user_grant(rgw_user& user_id);
7c673cae 378
f67539c2
TL
379 ACLGrantMap& get_grant_map() { return grant_map; }
380 const ACLGrantMap& get_grant_map() const { return grant_map; }
7c673cae
FG
381
382 void create_default(const rgw_user& id, string name) {
383 acl_user_map.clear();
384 acl_group_map.clear();
385 referer_list.clear();
386
387 ACLGrant grant;
388 grant.set_canon(id, name, RGW_PERM_FULL_CONTROL);
389 add_grant(&grant);
390 }
f67539c2
TL
391
392 friend bool operator==(const RGWAccessControlList& lhs, const RGWAccessControlList& rhs);
393 friend bool operator!=(const RGWAccessControlList& lhs, const RGWAccessControlList& rhs);
7c673cae
FG
394};
395WRITE_CLASS_ENCODER(RGWAccessControlList)
396
397class ACLOwner
398{
399protected:
400 rgw_user id;
401 string display_name;
402public:
403 ACLOwner() {}
f67539c2 404 ACLOwner(const rgw_user& _id) : id(_id) {}
7c673cae
FG
405 ~ACLOwner() {}
406
407 void encode(bufferlist& bl) const {
408 ENCODE_START(3, 2, bl);
409 string s;
410 id.to_str(s);
11fdf7f2
TL
411 encode(s, bl);
412 encode(display_name, bl);
7c673cae
FG
413 ENCODE_FINISH(bl);
414 }
11fdf7f2 415 void decode(bufferlist::const_iterator& bl) {
7c673cae
FG
416 DECODE_START_LEGACY_COMPAT_LEN(3, 2, 2, bl);
417 string s;
11fdf7f2 418 decode(s, bl);
7c673cae 419 id.from_str(s);
11fdf7f2 420 decode(display_name, bl);
7c673cae
FG
421 DECODE_FINISH(bl);
422 }
423 void dump(Formatter *f) const;
31f18b77 424 void decode_json(JSONObj *obj);
7c673cae
FG
425 static void generate_test_instances(list<ACLOwner*>& o);
426 void set_id(const rgw_user& _id) { id = _id; }
427 void set_name(const string& name) { display_name = name; }
428
429 rgw_user& get_id() { return id; }
430 const rgw_user& get_id() const { return id; }
431 string& get_display_name() { return display_name; }
f67539c2
TL
432 const string& get_display_name() const { return display_name; }
433 friend bool operator==(const ACLOwner& lhs, const ACLOwner& rhs);
434 friend bool operator!=(const ACLOwner& lhs, const ACLOwner& rhs);
7c673cae
FG
435};
436WRITE_CLASS_ENCODER(ACLOwner)
437
438class RGWAccessControlPolicy
439{
440protected:
441 CephContext *cct;
442 RGWAccessControlList acl;
443 ACLOwner owner;
444
445public:
446 explicit RGWAccessControlPolicy(CephContext *_cct) : cct(_cct), acl(_cct) {}
447 RGWAccessControlPolicy() : cct(NULL), acl(NULL) {}
448 virtual ~RGWAccessControlPolicy() {}
449
450 void set_ctx(CephContext *ctx) {
451 cct = ctx;
452 acl.set_ctx(ctx);
453 }
454
11fdf7f2
TL
455 uint32_t get_perm(const DoutPrefixProvider* dpp,
456 const rgw::auth::Identity& auth_identity,
7c673cae 457 uint32_t perm_mask,
9f95a23c
TL
458 const char * http_referer,
459 bool ignore_public_acls=false);
11fdf7f2
TL
460 bool verify_permission(const DoutPrefixProvider* dpp,
461 const rgw::auth::Identity& auth_identity,
7c673cae
FG
462 uint32_t user_perm_mask,
463 uint32_t perm,
9f95a23c
TL
464 const char * http_referer = nullptr,
465 bool ignore_public_acls=false);
7c673cae
FG
466
467 void encode(bufferlist& bl) const {
468 ENCODE_START(2, 2, bl);
11fdf7f2
TL
469 encode(owner, bl);
470 encode(acl, bl);
7c673cae
FG
471 ENCODE_FINISH(bl);
472 }
11fdf7f2 473 void decode(bufferlist::const_iterator& bl) {
7c673cae 474 DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl);
11fdf7f2
TL
475 decode(owner, bl);
476 decode(acl, bl);
7c673cae
FG
477 DECODE_FINISH(bl);
478 }
479 void dump(Formatter *f) const;
480 static void generate_test_instances(list<RGWAccessControlPolicy*>& o);
11fdf7f2 481 void decode_owner(bufferlist::const_iterator& bl) { // sometimes we only need that, should be faster
7c673cae 482 DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl);
11fdf7f2 483 decode(owner, bl);
7c673cae
FG
484 DECODE_FINISH(bl);
485 }
486
487 void set_owner(ACLOwner& o) { owner = o; }
488 ACLOwner& get_owner() {
489 return owner;
490 }
491
492 void create_default(const rgw_user& id, string& name) {
493 acl.create_default(id, name);
494 owner.set_id(id);
495 owner.set_name(name);
496 }
497 RGWAccessControlList& get_acl() {
498 return acl;
499 }
500 const RGWAccessControlList& get_acl() const {
501 return acl;
502 }
503
504 virtual bool compare_group_name(string& id, ACLGroupTypeEnum group) { return false; }
b3b6e05e 505 bool is_public(const DoutPrefixProvider *dpp) const;
f67539c2
TL
506
507 friend bool operator==(const RGWAccessControlPolicy& lhs, const RGWAccessControlPolicy& rhs);
508 friend bool operator!=(const RGWAccessControlPolicy& lhs, const RGWAccessControlPolicy& rhs);
7c673cae
FG
509};
510WRITE_CLASS_ENCODER(RGWAccessControlPolicy)
511
512#endif