Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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 #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
30 static constexpr char RGW_REFERER_WILDCARD[] = "*";
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 ("*" == url_spec) {
227       return true;
228     }
229
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);
245     ::encode(url_spec, bl);
246     ::encode(perm, bl);
247     ENCODE_FINISH(bl);
248   }
249   void decode(bufferlist::iterator& bl) {
250     DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, bl);
251     ::decode(url_spec, bl);
252     ::decode(perm, bl);
253     DECODE_FINISH(bl);
254   }
255   void dump(Formatter *f) const;
256
257 private:
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 };
277 WRITE_CLASS_ENCODER(ACLReferer)
278
279 namespace rgw {
280 namespace auth {
281   class Identity;
282 }
283 }
284
285 class RGWAccessControlList
286 {
287 protected:
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);
296 public:
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
306   uint32_t get_perm(const rgw::auth::Identity& auth_identity,
307                     uint32_t perm_mask);
308   uint32_t get_group_perm(ACLGroupTypeEnum group, uint32_t perm_mask);
309   uint32_t get_referer_perm(uint32_t current_perm,
310                             std::string http_referer,
311                             uint32_t perm_mask);
312   void encode(bufferlist& bl) const {
313     ENCODE_START(4, 3, bl);
314     bool maps_initialized = true;
315     ::encode(maps_initialized, bl);
316     ::encode(acl_user_map, bl);
317     ::encode(grant_map, bl);
318     ::encode(acl_group_map, bl);
319     ::encode(referer_list, bl);
320     ENCODE_FINISH(bl);
321   }
322   void decode(bufferlist::iterator& bl) {
323     DECODE_START_LEGACY_COMPAT_LEN(4, 3, 3, bl);
324     bool maps_initialized;
325     ::decode(maps_initialized, bl);
326     ::decode(acl_user_map, bl);
327     ::decode(grant_map, bl);
328     if (struct_v >= 2) {
329       ::decode(acl_group_map, bl);
330     } else if (!maps_initialized) {
331       multimap<string, ACLGrant>::iterator iter;
332       for (iter = grant_map.begin(); iter != grant_map.end(); ++iter) {
333         ACLGrant& grant = iter->second;
334         _add_grant(&grant);
335       }
336     }
337     if (struct_v >= 4) {
338       ::decode(referer_list, bl);
339     }
340     DECODE_FINISH(bl);
341   }
342   void dump(Formatter *f) const;
343   static void generate_test_instances(list<RGWAccessControlList*>& o);
344
345   void add_grant(ACLGrant *grant);
346
347   multimap<string, ACLGrant>& get_grant_map() { return grant_map; }
348   const multimap<string, ACLGrant>& get_grant_map() const { return grant_map; }
349
350   void create_default(const rgw_user& id, string name) {
351     acl_user_map.clear();
352     acl_group_map.clear();
353     referer_list.clear();
354
355     ACLGrant grant;
356     grant.set_canon(id, name, RGW_PERM_FULL_CONTROL);
357     add_grant(&grant);
358   }
359 };
360 WRITE_CLASS_ENCODER(RGWAccessControlList)
361
362 class ACLOwner
363 {
364 protected:
365   rgw_user id;
366   string display_name;
367 public:
368   ACLOwner() {}
369   ~ACLOwner() {}
370
371   void encode(bufferlist& bl) const {
372     ENCODE_START(3, 2, bl);
373     string s;
374     id.to_str(s);
375     ::encode(s, bl);
376     ::encode(display_name, bl);
377     ENCODE_FINISH(bl);
378   }
379   void decode(bufferlist::iterator& bl) {
380     DECODE_START_LEGACY_COMPAT_LEN(3, 2, 2, bl);
381     string s;
382     ::decode(s, bl);
383     id.from_str(s);
384     ::decode(display_name, bl);
385     DECODE_FINISH(bl);
386   }
387   void dump(Formatter *f) const;
388   void decode_json(JSONObj *obj);
389   static void generate_test_instances(list<ACLOwner*>& o);
390   void set_id(const rgw_user& _id) { id = _id; }
391   void set_name(const string& name) { display_name = name; }
392
393   rgw_user& get_id() { return id; }
394   const rgw_user& get_id() const { return id; }
395   string& get_display_name() { return display_name; }
396 };
397 WRITE_CLASS_ENCODER(ACLOwner)
398
399 class RGWAccessControlPolicy
400 {
401 protected:
402   CephContext *cct;
403   RGWAccessControlList acl;
404   ACLOwner owner;
405
406 public:
407   explicit RGWAccessControlPolicy(CephContext *_cct) : cct(_cct), acl(_cct) {}
408   RGWAccessControlPolicy() : cct(NULL), acl(NULL) {}
409   virtual ~RGWAccessControlPolicy() {}
410
411   void set_ctx(CephContext *ctx) {
412     cct = ctx;
413     acl.set_ctx(ctx);
414   }
415
416   uint32_t get_perm(const rgw::auth::Identity& auth_identity,
417                     uint32_t perm_mask,
418                     const char * http_referer);
419   uint32_t get_group_perm(ACLGroupTypeEnum group, uint32_t perm_mask);
420   bool verify_permission(const rgw::auth::Identity& auth_identity,
421                          uint32_t user_perm_mask,
422                          uint32_t perm,
423                          const char * http_referer = nullptr);
424
425   void encode(bufferlist& bl) const {
426     ENCODE_START(2, 2, bl);
427     ::encode(owner, bl);
428     ::encode(acl, bl);
429     ENCODE_FINISH(bl);
430   }
431   void decode(bufferlist::iterator& bl) {
432     DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl);
433     ::decode(owner, bl);
434     ::decode(acl, bl);
435     DECODE_FINISH(bl);
436   }
437   void dump(Formatter *f) const;
438   static void generate_test_instances(list<RGWAccessControlPolicy*>& o);
439   void decode_owner(bufferlist::iterator& bl) { // sometimes we only need that, should be faster
440     DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl);
441     ::decode(owner, bl);
442     DECODE_FINISH(bl);
443   }
444
445   void set_owner(ACLOwner& o) { owner = o; }
446   ACLOwner& get_owner() {
447     return owner;
448   }
449
450   void create_default(const rgw_user& id, string& name) {
451     acl.create_default(id, name);
452     owner.set_id(id);
453     owner.set_name(name);
454   }
455   RGWAccessControlList& get_acl() {
456     return acl;
457   }
458   const RGWAccessControlList& get_acl() const {
459     return acl;
460   }
461
462   virtual bool compare_group_name(string& id, ACLGroupTypeEnum group) { return false; }
463 };
464 WRITE_CLASS_ENCODER(RGWAccessControlPolicy)
465
466 #endif