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"
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
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 (http_host
->compare(url_spec
) == 0) {
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
);
239 void encode(bufferlist
& bl
) const {
240 ENCODE_START(1, 1, bl
);
241 ::encode(url_spec
, bl
);
245 void decode(bufferlist::iterator
& bl
) {
246 DECODE_START_LEGACY_COMPAT_LEN(1, 1, 1, bl
);
247 ::decode(url_spec
, bl
);
251 void dump(Formatter
*f
) const;
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('@')) {
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);
265 pos
= url_sub
.find_first_of("/:");
266 if (pos
== boost::string_ref::npos
) {
267 /* no port or path exists */
270 return url_sub
.substr(0, pos
);
273 WRITE_CLASS_ENCODER(ACLReferer
)
281 class RGWAccessControlList
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
);
293 explicit RGWAccessControlList(CephContext
*_cct
) : cct(_cct
) {}
294 RGWAccessControlList() : cct(NULL
) {}
296 void set_ctx(CephContext
*ctx
) {
300 virtual ~RGWAccessControlList() {}
302 uint32_t get_perm(const rgw::auth::Identity
& auth_identity
,
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
);
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
);
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
;
332 ::decode(referer_list
, bl
);
336 void dump(Formatter
*f
) const;
337 static void generate_test_instances(list
<RGWAccessControlList
*>& o
);
339 void add_grant(ACLGrant
*grant
);
341 multimap
<string
, ACLGrant
>& get_grant_map() { return grant_map
; }
342 const multimap
<string
, ACLGrant
>& get_grant_map() const { return grant_map
; }
344 void create_default(const rgw_user
& id
, string name
) {
345 acl_user_map
.clear();
346 acl_group_map
.clear();
347 referer_list
.clear();
350 grant
.set_canon(id
, name
, RGW_PERM_FULL_CONTROL
);
354 WRITE_CLASS_ENCODER(RGWAccessControlList
)
365 void encode(bufferlist
& bl
) const {
366 ENCODE_START(3, 2, bl
);
370 ::encode(display_name
, bl
);
373 void decode(bufferlist::iterator
& bl
) {
374 DECODE_START_LEGACY_COMPAT_LEN(3, 2, 2, bl
);
378 ::decode(display_name
, bl
);
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
; }
386 rgw_user
& get_id() { return id
; }
387 const rgw_user
& get_id() const { return id
; }
388 string
& get_display_name() { return display_name
; }
390 WRITE_CLASS_ENCODER(ACLOwner
)
392 class RGWAccessControlPolicy
396 RGWAccessControlList acl
;
400 explicit RGWAccessControlPolicy(CephContext
*_cct
) : cct(_cct
), acl(_cct
) {}
401 RGWAccessControlPolicy() : cct(NULL
), acl(NULL
) {}
402 virtual ~RGWAccessControlPolicy() {}
404 void set_ctx(CephContext
*ctx
) {
409 uint32_t get_perm(const rgw::auth::Identity
& auth_identity
,
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
,
416 const char * http_referer
= nullptr);
418 void encode(bufferlist
& bl
) const {
419 ENCODE_START(2, 2, bl
);
424 void decode(bufferlist::iterator
& bl
) {
425 DECODE_START_LEGACY_COMPAT_LEN(2, 2, 2, bl
);
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
);
438 void set_owner(ACLOwner
& o
) { owner
= o
; }
439 ACLOwner
& get_owner() {
443 void create_default(const rgw_user
& id
, string
& name
) {
444 acl
.create_default(id
, name
);
446 owner
.set_name(name
);
448 RGWAccessControlList
& get_acl() {
451 const RGWAccessControlList
& get_acl() const {
455 virtual bool compare_group_name(string
& id
, ACLGroupTypeEnum group
) { return false; }
457 WRITE_CLASS_ENCODER(RGWAccessControlPolicy
)