]>
Commit | Line | Data |
---|---|---|
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 |
30 | static constexpr char RGW_REFERER_WILDCARD[] = "*"; |
31 | ||
7c673cae FG |
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); | |
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 | }; | |
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); | |
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 | }; | |
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); | |
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 | }; | |
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 | ||
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 | ||
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 | ||
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 | }; | |
362 | WRITE_CLASS_ENCODER(RGWAccessControlList) | |
363 | ||
364 | class ACLOwner | |
365 | { | |
366 | protected: | |
367 | rgw_user id; | |
368 | string display_name; | |
369 | public: | |
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 | }; | |
399 | WRITE_CLASS_ENCODER(ACLOwner) | |
400 | ||
401 | class RGWAccessControlPolicy | |
402 | { | |
403 | protected: | |
404 | CephContext *cct; | |
405 | RGWAccessControlList acl; | |
406 | ACLOwner owner; | |
407 | ||
408 | public: | |
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 | }; |
470 | WRITE_CLASS_ENCODER(RGWAccessControlPolicy) | |
471 | ||
472 | #endif |