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