1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
9 #include <include/types.h>
11 #include <boost/optional.hpp>
12 #include <boost/utility/string_ref.hpp>
14 #include "common/debug.h"
16 #include "rgw_basic_types.h"
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
30 static constexpr char RGW_REFERER_WILDCARD
[] = "*";
32 enum ACLGranteeTypeEnum
{
33 /* numbers are encoded, should not change */
34 ACL_TYPE_CANON_USER
= 0,
35 ACL_TYPE_EMAIL_USER
= 1,
41 enum ACLGroupTypeEnum
{
42 /* numbers are encoded should not change */
44 ACL_GROUP_ALL_USERS
= 1,
45 ACL_GROUP_AUTHENTICATED_USERS
= 2,
53 ACLPermission() : flags(0) {}
55 uint32_t get_permissions() const { return flags
; }
56 void set_permissions(uint32_t perm
) { flags
= perm
; }
58 void encode(bufferlist
& bl
) const {
59 ENCODE_START(2, 2, bl
);
63 void decode(bufferlist::iterator
& bl
) {
64 DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl
);
68 void dump(Formatter
*f
) const;
69 static void generate_test_instances(list
<ACLPermission
*>& o
);
71 WRITE_CLASS_ENCODER(ACLPermission
)
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
);
89 void decode(bufferlist::iterator
& bl
) {
90 DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl
);
94 void dump(Formatter
*f
) const;
95 static void generate_test_instances(list
<ACLGranteeType
*>& o
);
97 WRITE_CLASS_ENCODER(ACLGranteeType
)
113 ACLPermission permission
;
115 ACLGroupTypeEnum group
;
119 ACLGrant() : group(ACL_GROUP_NONE
) {}
120 virtual ~ACLGrant() {}
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
130 case ACL_TYPE_REFERER
:
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
; }
144 void encode(bufferlist
& bl
) const {
145 ENCODE_START(5, 3, bl
);
153 ::encode(permission
, bl
);
155 __u32 g
= (__u32
)group
;
157 ::encode(url_spec
, bl
);
160 void decode(bufferlist::iterator
& bl
) {
161 DECODE_START_LEGACY_COMPAT_LEN(5, 3, 3, bl
);
169 ::decode(permission
, bl
);
174 group
= (ACLGroupTypeEnum
)g
;
176 group
= uri_to_group(uri
);
179 ::decode(url_spec
, bl
);
185 void dump(Formatter
*f
) const;
186 static void generate_test_instances(list
<ACLGrant
*>& o
);
188 ACLGroupTypeEnum
uri_to_group(string
& uri
);
190 void set_canon(const rgw_user
& _id
, const string
& _name
, const uint32_t perm
) {
191 type
.set(ACL_TYPE_CANON_USER
);
194 permission
.set_permissions(perm
);
196 void set_group(ACLGroupTypeEnum _group
, const uint32_t perm
) {
197 type
.set(ACL_TYPE_GROUP
);
199 permission
.set_permissions(perm
);
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
);
207 WRITE_CLASS_ENCODER(ACLGrant
)
210 std::string url_spec
;
213 ACLReferer() : perm(0) {}
214 ACLReferer(const std::string
& url_spec
,
216 : url_spec(url_spec
),
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()) {
226 if ("*" == url_spec
) {
230 if (http_host
->compare(url_spec
) == 0) {
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
);
243 void encode(bufferlist
& bl
) const {
244 ENCODE_START(1, 1, bl
);
245 ::encode(url_spec
, bl
);
249 void decode(bufferlist::iterator
& bl
) {
250 DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, bl
);
251 ::decode(url_spec
, bl
);
255 void dump(Formatter
*f
) const;
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('@')) {
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);
269 pos
= url_sub
.find_first_of("/:");
270 if (pos
== boost::string_ref::npos
) {
271 /* no port or path exists */
274 return url_sub
.substr(0, pos
);
277 WRITE_CLASS_ENCODER(ACLReferer
)
285 class RGWAccessControlList
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
);
297 explicit RGWAccessControlList(CephContext
*_cct
) : cct(_cct
) {}
298 RGWAccessControlList() : cct(NULL
) {}
300 void set_ctx(CephContext
*ctx
) {
304 virtual ~RGWAccessControlList() {}
306 uint32_t get_perm(const rgw::auth::Identity
& auth_identity
,
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
,
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
);
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
);
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
;
338 ::decode(referer_list
, bl
);
342 void dump(Formatter
*f
) const;
343 static void generate_test_instances(list
<RGWAccessControlList
*>& o
);
345 void add_grant(ACLGrant
*grant
);
347 multimap
<string
, ACLGrant
>& get_grant_map() { return grant_map
; }
348 const multimap
<string
, ACLGrant
>& get_grant_map() const { return grant_map
; }
350 void create_default(const rgw_user
& id
, string name
) {
351 acl_user_map
.clear();
352 acl_group_map
.clear();
353 referer_list
.clear();
356 grant
.set_canon(id
, name
, RGW_PERM_FULL_CONTROL
);
360 WRITE_CLASS_ENCODER(RGWAccessControlList
)
371 void encode(bufferlist
& bl
) const {
372 ENCODE_START(3, 2, bl
);
376 ::encode(display_name
, bl
);
379 void decode(bufferlist::iterator
& bl
) {
380 DECODE_START_LEGACY_COMPAT_LEN(3, 2, 2, bl
);
384 ::decode(display_name
, bl
);
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
; }
393 rgw_user
& get_id() { return id
; }
394 const rgw_user
& get_id() const { return id
; }
395 string
& get_display_name() { return display_name
; }
397 WRITE_CLASS_ENCODER(ACLOwner
)
399 class RGWAccessControlPolicy
403 RGWAccessControlList acl
;
407 explicit RGWAccessControlPolicy(CephContext
*_cct
) : cct(_cct
), acl(_cct
) {}
408 RGWAccessControlPolicy() : cct(NULL
), acl(NULL
) {}
409 virtual ~RGWAccessControlPolicy() {}
411 void set_ctx(CephContext
*ctx
) {
416 uint32_t get_perm(const rgw::auth::Identity
& auth_identity
,
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
,
423 const char * http_referer
= nullptr);
425 void encode(bufferlist
& bl
) const {
426 ENCODE_START(2, 2, bl
);
431 void decode(bufferlist::iterator
& bl
) {
432 DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl
);
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
);
445 void set_owner(ACLOwner
& o
) { owner
= o
; }
446 ACLOwner
& get_owner() {
450 void create_default(const rgw_user
& id
, string
& name
) {
451 acl
.create_default(id
, name
);
453 owner
.set_name(name
);
455 RGWAccessControlList
& get_acl() {
458 const RGWAccessControlList
& get_acl() const {
462 virtual bool compare_group_name(string
& id
, ACLGroupTypeEnum group
) { return false; }
464 WRITE_CLASS_ENCODER(RGWAccessControlPolicy
)