]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_acl.h
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / rgw / rgw_acl.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_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
18 using namespace std;
19
20 #define RGW_PERM_NONE 0x00
21 #define RGW_PERM_READ 0x01
22 #define RGW_PERM_WRITE 0x02
23 #define RGW_PERM_READ_ACP 0x04
24 #define RGW_PERM_WRITE_ACP 0x08
25 #define RGW_PERM_READ_OBJS 0x10
26 #define RGW_PERM_WRITE_OBJS 0x20
27 #define RGW_PERM_FULL_CONTROL ( RGW_PERM_READ | RGW_PERM_WRITE | \
28 RGW_PERM_READ_ACP | RGW_PERM_WRITE_ACP )
29 #define RGW_PERM_ALL_S3 RGW_PERM_FULL_CONTROL
30 #define RGW_PERM_INVALID 0xFF00
31
32 enum 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
41 enum 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
48 class ACLPermission
49 {
50 protected:
51 int flags;
52 public:
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);
60 ::encode(flags, bl);
61 ENCODE_FINISH(bl);
62 }
63 void decode(bufferlist::iterator& bl) {
64 DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl);
65 ::decode(flags, bl);
66 DECODE_FINISH(bl);
67 }
68 void dump(Formatter *f) const;
69 static void generate_test_instances(list<ACLPermission*>& o);
70 };
71 WRITE_CLASS_ENCODER(ACLPermission)
72
73 class ACLGranteeType
74 {
75 protected:
76 __u32 type;
77 public:
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);
86 ::encode(type, bl);
87 ENCODE_FINISH(bl);
88 }
89 void decode(bufferlist::iterator& bl) {
90 DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl);
91 ::decode(type, bl);
92 DECODE_FINISH(bl);
93 }
94 void dump(Formatter *f) const;
95 static void generate_test_instances(list<ACLGranteeType*>& o);
96 };
97 WRITE_CLASS_ENCODER(ACLGranteeType)
98
99 class ACLGrantee
100 {
101 public:
102 ACLGrantee() {}
103 ~ACLGrantee() {}
104 };
105
106
107 class ACLGrant
108 {
109 protected:
110 ACLGranteeType type;
111 rgw_user id;
112 string email;
113 ACLPermission permission;
114 string name;
115 ACLGroupTypeEnum group;
116 string url_spec;
117
118 public:
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);
146 ::encode(type, bl);
147 string s;
148 id.to_str(s);
149 ::encode(s, bl);
150 string uri;
151 ::encode(uri, bl);
152 ::encode(email, bl);
153 ::encode(permission, bl);
154 ::encode(name, bl);
155 __u32 g = (__u32)group;
156 ::encode(g, bl);
157 ::encode(url_spec, bl);
158 ENCODE_FINISH(bl);
159 }
160 void decode(bufferlist::iterator& bl) {
161 DECODE_START_LEGACY_COMPAT_LEN(5, 3, 3, bl);
162 ::decode(type, bl);
163 string s;
164 ::decode(s, bl);
165 id.from_str(s);
166 string uri;
167 ::decode(uri, bl);
168 ::decode(email, bl);
169 ::decode(permission, bl);
170 ::decode(name, bl);
171 if (struct_v > 1) {
172 __u32 g;
173 ::decode(g, bl);
174 group = (ACLGroupTypeEnum)g;
175 } else {
176 group = uri_to_group(uri);
177 }
178 if (struct_v >= 5) {
179 ::decode(url_spec, bl);
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 };
207 WRITE_CLASS_ENCODER(ACLGrant)
208
209 struct 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
226 if (http_host->compare(url_spec) == 0) {
227 return true;
228 }
229
230 if ('.' == url_spec[0]) {
231 /* Wildcard support: a referer matches the spec when its last char are
232 * perfectly equal to spec. */
233 return http_host->ends_with(url_spec);
234 }
235
236 return false;
237 }
238
239 void encode(bufferlist& bl) const {
240 ENCODE_START(1, 1, bl);
241 ::encode(url_spec, bl);
242 ::encode(perm, bl);
243 ENCODE_FINISH(bl);
244 }
245 void decode(bufferlist::iterator& bl) {
246 DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, bl);
247 ::decode(url_spec, bl);
248 ::decode(perm, bl);
249 DECODE_FINISH(bl);
250 }
251 void dump(Formatter *f) const;
252
253 private:
254 boost::optional<boost::string_ref> get_http_host(const boost::string_ref url) const {
255 size_t pos = url.find("://");
256 if (pos == boost::string_ref::npos || url.starts_with("://") ||
257 url.ends_with("://") || url.ends_with('@')) {
258 return boost::none;
259 }
260 boost::string_ref url_sub = url.substr(pos + strlen("://"));
261 pos = url_sub.find('@');
262 if (pos != boost::string_ref::npos) {
263 url_sub = url_sub.substr(pos + 1);
264 }
265 pos = url_sub.find_first_of("/:");
266 if (pos == boost::string_ref::npos) {
267 /* no port or path exists */
268 return url_sub;
269 }
270 return url_sub.substr(0, pos);
271 }
272 };
273 WRITE_CLASS_ENCODER(ACLReferer)
274
275 namespace rgw {
276 namespace auth {
277 class Identity;
278 }
279 }
280
281 class RGWAccessControlList
282 {
283 protected:
284 CephContext *cct;
285 /* FIXME: in the feature we should consider switching to uint32_t also
286 * in data structures. */
287 map<string, int> acl_user_map;
288 map<uint32_t, int> acl_group_map;
289 list<ACLReferer> referer_list;
290 multimap<string, ACLGrant> grant_map;
291 void _add_grant(ACLGrant *grant);
292 public:
293 explicit RGWAccessControlList(CephContext *_cct) : cct(_cct) {}
294 RGWAccessControlList() : cct(NULL) {}
295
296 void set_ctx(CephContext *ctx) {
297 cct = ctx;
298 }
299
300 virtual ~RGWAccessControlList() {}
301
302 uint32_t get_perm(const rgw::auth::Identity& auth_identity,
303 uint32_t perm_mask);
304 uint32_t get_group_perm(ACLGroupTypeEnum group, uint32_t perm_mask);
305 uint32_t get_referer_perm(const std::string http_referer, uint32_t perm_mask);
306 void encode(bufferlist& bl) const {
307 ENCODE_START(4, 3, bl);
308 bool maps_initialized = true;
309 ::encode(maps_initialized, bl);
310 ::encode(acl_user_map, bl);
311 ::encode(grant_map, bl);
312 ::encode(acl_group_map, bl);
313 ::encode(referer_list, bl);
314 ENCODE_FINISH(bl);
315 }
316 void decode(bufferlist::iterator& bl) {
317 DECODE_START_LEGACY_COMPAT_LEN(4, 3, 3, bl);
318 bool maps_initialized;
319 ::decode(maps_initialized, bl);
320 ::decode(acl_user_map, bl);
321 ::decode(grant_map, bl);
322 if (struct_v >= 2) {
323 ::decode(acl_group_map, bl);
324 } else if (!maps_initialized) {
325 multimap<string, ACLGrant>::iterator iter;
326 for (iter = grant_map.begin(); iter != grant_map.end(); ++iter) {
327 ACLGrant& grant = iter->second;
328 _add_grant(&grant);
329 }
330 }
331 if (struct_v >= 4) {
332 ::decode(referer_list, bl);
333 }
334 DECODE_FINISH(bl);
335 }
336 void dump(Formatter *f) const;
337 static void generate_test_instances(list<RGWAccessControlList*>& o);
338
339 void add_grant(ACLGrant *grant);
340
341 multimap<string, ACLGrant>& get_grant_map() { return grant_map; }
342 const multimap<string, ACLGrant>& get_grant_map() const { return grant_map; }
343
344 void create_default(const rgw_user& id, string name) {
345 acl_user_map.clear();
346 acl_group_map.clear();
347 referer_list.clear();
348
349 ACLGrant grant;
350 grant.set_canon(id, name, RGW_PERM_FULL_CONTROL);
351 add_grant(&grant);
352 }
353 };
354 WRITE_CLASS_ENCODER(RGWAccessControlList)
355
356 class ACLOwner
357 {
358 protected:
359 rgw_user id;
360 string display_name;
361 public:
362 ACLOwner() {}
363 ~ACLOwner() {}
364
365 void encode(bufferlist& bl) const {
366 ENCODE_START(3, 2, bl);
367 string s;
368 id.to_str(s);
369 ::encode(s, bl);
370 ::encode(display_name, bl);
371 ENCODE_FINISH(bl);
372 }
373 void decode(bufferlist::iterator& bl) {
374 DECODE_START_LEGACY_COMPAT_LEN(3, 2, 2, bl);
375 string s;
376 ::decode(s, bl);
377 id.from_str(s);
378 ::decode(display_name, bl);
379 DECODE_FINISH(bl);
380 }
381 void dump(Formatter *f) const;
382 static void generate_test_instances(list<ACLOwner*>& o);
383 void set_id(const rgw_user& _id) { id = _id; }
384 void set_name(const string& name) { display_name = name; }
385
386 rgw_user& get_id() { return id; }
387 const rgw_user& get_id() const { return id; }
388 string& get_display_name() { return display_name; }
389 };
390 WRITE_CLASS_ENCODER(ACLOwner)
391
392 class RGWAccessControlPolicy
393 {
394 protected:
395 CephContext *cct;
396 RGWAccessControlList acl;
397 ACLOwner owner;
398
399 public:
400 explicit RGWAccessControlPolicy(CephContext *_cct) : cct(_cct), acl(_cct) {}
401 RGWAccessControlPolicy() : cct(NULL), acl(NULL) {}
402 virtual ~RGWAccessControlPolicy() {}
403
404 void set_ctx(CephContext *ctx) {
405 cct = ctx;
406 acl.set_ctx(ctx);
407 }
408
409 uint32_t get_perm(const rgw::auth::Identity& auth_identity,
410 uint32_t perm_mask,
411 const char * http_referer);
412 uint32_t get_group_perm(ACLGroupTypeEnum group, uint32_t perm_mask);
413 bool verify_permission(const rgw::auth::Identity& auth_identity,
414 uint32_t user_perm_mask,
415 uint32_t perm,
416 const char * http_referer = nullptr);
417
418 void encode(bufferlist& bl) const {
419 ENCODE_START(2, 2, bl);
420 ::encode(owner, bl);
421 ::encode(acl, bl);
422 ENCODE_FINISH(bl);
423 }
424 void decode(bufferlist::iterator& bl) {
425 DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl);
426 ::decode(owner, bl);
427 ::decode(acl, bl);
428 DECODE_FINISH(bl);
429 }
430 void dump(Formatter *f) const;
431 static void generate_test_instances(list<RGWAccessControlPolicy*>& o);
432 void decode_owner(bufferlist::iterator& bl) { // sometimes we only need that, should be faster
433 DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl);
434 ::decode(owner, bl);
435 DECODE_FINISH(bl);
436 }
437
438 void set_owner(ACLOwner& o) { owner = o; }
439 ACLOwner& get_owner() {
440 return owner;
441 }
442
443 void create_default(const rgw_user& id, string& name) {
444 acl.create_default(id, name);
445 owner.set_id(id);
446 owner.set_name(name);
447 }
448 RGWAccessControlList& get_acl() {
449 return acl;
450 }
451 const RGWAccessControlList& get_acl() const {
452 return acl;
453 }
454
455 virtual bool compare_group_name(string& id, ACLGroupTypeEnum group) { return false; }
456 };
457 WRITE_CLASS_ENCODER(RGWAccessControlPolicy)
458
459 #endif