1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
10 #include <include/types.h>
12 #include <boost/optional.hpp>
13 #include <boost/algorithm/string/predicate.hpp>
15 #include "common/debug.h"
17 #include "rgw_basic_types.h"
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
31 static constexpr char RGW_REFERER_WILDCARD
[] = "*";
33 enum ACLGranteeTypeEnum
{
34 /* numbers are encoded, should not change */
35 ACL_TYPE_CANON_USER
= 0,
36 ACL_TYPE_EMAIL_USER
= 1,
42 enum ACLGroupTypeEnum
{
43 /* numbers are encoded should not change */
45 ACL_GROUP_ALL_USERS
= 1,
46 ACL_GROUP_AUTHENTICATED_USERS
= 2,
54 ACLPermission() : flags(0) {}
56 uint32_t get_permissions() const { return flags
; }
57 void set_permissions(uint32_t perm
) { flags
= perm
; }
59 void encode(bufferlist
& bl
) const {
60 ENCODE_START(2, 2, bl
);
64 void decode(bufferlist::const_iterator
& bl
) {
65 DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl
);
69 void dump(Formatter
*f
) const;
70 static void generate_test_instances(list
<ACLPermission
*>& o
);
72 friend bool operator==(const ACLPermission
& lhs
, const ACLPermission
& rhs
);
73 friend bool operator!=(const ACLPermission
& lhs
, const ACLPermission
& rhs
);
75 WRITE_CLASS_ENCODER(ACLPermission
)
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
);
93 void decode(bufferlist::const_iterator
& bl
) {
94 DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl
);
98 void dump(Formatter
*f
) const;
99 static void generate_test_instances(list
<ACLGranteeType
*>& o
);
101 friend bool operator==(const ACLGranteeType
& lhs
, const ACLGranteeType
& rhs
);
102 friend bool operator!=(const ACLGranteeType
& lhs
, const ACLGranteeType
& rhs
);
104 WRITE_CLASS_ENCODER(ACLGranteeType
)
120 mutable rgw_user email_id
;
121 ACLPermission permission
;
123 ACLGroupTypeEnum group
;
127 ACLGrant() : group(ACL_GROUP_NONE
) {}
128 virtual ~ACLGrant() {}
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
138 case ACL_TYPE_REFERER
:
146 const rgw_user
* get_id() const {
147 switch(type
.get_type()) {
148 case ACL_TYPE_EMAIL_USER
:
149 email_id
.from_str(email
);
152 case ACL_TYPE_REFERER
:
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
; }
166 void encode(bufferlist
& bl
) const {
167 ENCODE_START(5, 3, bl
);
175 encode(permission
, bl
);
177 __u32 g
= (__u32
)group
;
179 encode(url_spec
, bl
);
182 void decode(bufferlist::const_iterator
& bl
) {
183 DECODE_START_LEGACY_COMPAT_LEN(5, 3, 3, bl
);
191 decode(permission
, bl
);
196 group
= (ACLGroupTypeEnum
)g
;
198 group
= uri_to_group(uri
);
201 decode(url_spec
, bl
);
207 void dump(Formatter
*f
) const;
208 static void generate_test_instances(list
<ACLGrant
*>& o
);
210 ACLGroupTypeEnum
uri_to_group(string
& uri
);
212 void set_canon(const rgw_user
& _id
, const string
& _name
, const uint32_t perm
) {
213 type
.set(ACL_TYPE_CANON_USER
);
216 permission
.set_permissions(perm
);
218 void set_group(ACLGroupTypeEnum _group
, const uint32_t perm
) {
219 type
.set(ACL_TYPE_GROUP
);
221 permission
.set_permissions(perm
);
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
);
229 friend bool operator==(const ACLGrant
& lhs
, const ACLGrant
& rhs
);
230 friend bool operator!=(const ACLGrant
& lhs
, const ACLGrant
& rhs
);
232 WRITE_CLASS_ENCODER(ACLGrant
)
235 std::string url_spec
;
238 ACLReferer() : perm(0) {}
239 ACLReferer(const std::string
& url_spec
,
241 : url_spec(url_spec
),
245 bool is_match(std::string_view http_referer
) const {
246 const auto http_host
= get_http_host(http_referer
);
247 if (!http_host
|| http_host
->length() < url_spec
.length()) {
251 if ("*" == url_spec
) {
255 if (http_host
->compare(url_spec
) == 0) {
259 if ('.' == url_spec
[0]) {
260 /* Wildcard support: a referer matches the spec when its last char are
261 * perfectly equal to spec. */
262 return boost::algorithm::ends_with(http_host
.value(), url_spec
);
268 void encode(bufferlist
& bl
) const {
269 ENCODE_START(1, 1, bl
);
270 encode(url_spec
, bl
);
274 void decode(bufferlist::const_iterator
& bl
) {
275 DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, bl
);
276 decode(url_spec
, bl
);
280 void dump(Formatter
*f
) const;
282 friend bool operator==(const ACLReferer
& lhs
, const ACLReferer
& rhs
);
283 friend bool operator!=(const ACLReferer
& lhs
, const ACLReferer
& rhs
);
286 boost::optional
<std::string_view
> get_http_host(const std::string_view url
) const {
287 size_t pos
= url
.find("://");
288 if (pos
== std::string_view::npos
|| boost::algorithm::starts_with(url
, "://") ||
289 boost::algorithm::ends_with(url
, "://") || boost::algorithm::ends_with(url
, "@")) {
292 std::string_view url_sub
= url
.substr(pos
+ strlen("://"));
293 pos
= url_sub
.find('@');
294 if (pos
!= std::string_view::npos
) {
295 url_sub
= url_sub
.substr(pos
+ 1);
297 pos
= url_sub
.find_first_of("/:");
298 if (pos
== std::string_view::npos
) {
299 /* no port or path exists */
302 return url_sub
.substr(0, pos
);
305 WRITE_CLASS_ENCODER(ACLReferer
)
313 using ACLGrantMap
= std::multimap
<std::string
, ACLGrant
>;
315 class RGWAccessControlList
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
;
324 ACLGrantMap grant_map
;
325 void _add_grant(ACLGrant
*grant
);
327 explicit RGWAccessControlList(CephContext
*_cct
) : cct(_cct
) {}
328 RGWAccessControlList() : cct(NULL
) {}
330 void set_ctx(CephContext
*ctx
) {
334 virtual ~RGWAccessControlList() {}
336 uint32_t get_perm(const DoutPrefixProvider
* dpp
,
337 const rgw::auth::Identity
& auth_identity
,
339 uint32_t get_group_perm(const DoutPrefixProvider
*dpp
, ACLGroupTypeEnum group
, uint32_t perm_mask
) const;
340 uint32_t get_referer_perm(uint32_t current_perm
,
341 std::string http_referer
,
343 void encode(bufferlist
& bl
) const {
344 ENCODE_START(4, 3, bl
);
345 bool maps_initialized
= true;
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
);
353 void decode(bufferlist::const_iterator
& bl
) {
354 DECODE_START_LEGACY_COMPAT_LEN(4, 3, 3, bl
);
355 bool maps_initialized
;
356 decode(maps_initialized
, bl
);
357 decode(acl_user_map
, bl
);
358 decode(grant_map
, bl
);
360 decode(acl_group_map
, bl
);
361 } else if (!maps_initialized
) {
362 ACLGrantMap::iterator iter
;
363 for (iter
= grant_map
.begin(); iter
!= grant_map
.end(); ++iter
) {
364 ACLGrant
& grant
= iter
->second
;
369 decode(referer_list
, bl
);
373 void dump(Formatter
*f
) const;
374 static void generate_test_instances(list
<RGWAccessControlList
*>& o
);
376 void add_grant(ACLGrant
*grant
);
377 void remove_canon_user_grant(rgw_user
& user_id
);
379 ACLGrantMap
& get_grant_map() { return grant_map
; }
380 const ACLGrantMap
& get_grant_map() const { return grant_map
; }
382 void create_default(const rgw_user
& id
, string name
) {
383 acl_user_map
.clear();
384 acl_group_map
.clear();
385 referer_list
.clear();
388 grant
.set_canon(id
, name
, RGW_PERM_FULL_CONTROL
);
392 friend bool operator==(const RGWAccessControlList
& lhs
, const RGWAccessControlList
& rhs
);
393 friend bool operator!=(const RGWAccessControlList
& lhs
, const RGWAccessControlList
& rhs
);
395 WRITE_CLASS_ENCODER(RGWAccessControlList
)
404 ACLOwner(const rgw_user
& _id
) : id(_id
) {}
407 void encode(bufferlist
& bl
) const {
408 ENCODE_START(3, 2, bl
);
412 encode(display_name
, bl
);
415 void decode(bufferlist::const_iterator
& bl
) {
416 DECODE_START_LEGACY_COMPAT_LEN(3, 2, 2, bl
);
420 decode(display_name
, bl
);
423 void dump(Formatter
*f
) const;
424 void decode_json(JSONObj
*obj
);
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
; }
429 rgw_user
& get_id() { return id
; }
430 const rgw_user
& get_id() const { return id
; }
431 string
& get_display_name() { return display_name
; }
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
);
436 WRITE_CLASS_ENCODER(ACLOwner
)
438 class RGWAccessControlPolicy
442 RGWAccessControlList acl
;
446 explicit RGWAccessControlPolicy(CephContext
*_cct
) : cct(_cct
), acl(_cct
) {}
447 RGWAccessControlPolicy() : cct(NULL
), acl(NULL
) {}
448 virtual ~RGWAccessControlPolicy() {}
450 void set_ctx(CephContext
*ctx
) {
455 uint32_t get_perm(const DoutPrefixProvider
* dpp
,
456 const rgw::auth::Identity
& auth_identity
,
458 const char * http_referer
,
459 bool ignore_public_acls
=false);
460 bool verify_permission(const DoutPrefixProvider
* dpp
,
461 const rgw::auth::Identity
& auth_identity
,
462 uint32_t user_perm_mask
,
464 const char * http_referer
= nullptr,
465 bool ignore_public_acls
=false);
467 void encode(bufferlist
& bl
) const {
468 ENCODE_START(2, 2, bl
);
473 void decode(bufferlist::const_iterator
& bl
) {
474 DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl
);
479 void dump(Formatter
*f
) const;
480 static void generate_test_instances(list
<RGWAccessControlPolicy
*>& o
);
481 void decode_owner(bufferlist::const_iterator
& bl
) { // sometimes we only need that, should be faster
482 DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl
);
487 void set_owner(ACLOwner
& o
) { owner
= o
; }
488 ACLOwner
& get_owner() {
492 void create_default(const rgw_user
& id
, string
& name
) {
493 acl
.create_default(id
, name
);
495 owner
.set_name(name
);
497 RGWAccessControlList
& get_acl() {
500 const RGWAccessControlList
& get_acl() const {
504 virtual bool compare_group_name(string
& id
, ACLGroupTypeEnum group
) { return false; }
505 bool is_public(const DoutPrefixProvider
*dpp
) const;
507 friend bool operator==(const RGWAccessControlPolicy
& lhs
, const RGWAccessControlPolicy
& rhs
);
508 friend bool operator!=(const RGWAccessControlPolicy
& lhs
, const RGWAccessControlPolicy
& rhs
);
510 WRITE_CLASS_ENCODER(RGWAccessControlPolicy
)