]> git.proxmox.com Git - ceph.git/blob - ceph/src/rgw/rgw_acl_swift.cc
bump version to 18.2.2-pve1
[ceph.git] / ceph / src / rgw / rgw_acl_swift.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab ft=cpp
3
4 #include <string.h>
5
6 #include <vector>
7
8 #include <boost/algorithm/string/predicate.hpp>
9
10 #include "common/ceph_json.h"
11 #include "rgw_common.h"
12 #include "rgw_user.h"
13 #include "rgw_acl_swift.h"
14 #include "rgw_sal.h"
15
16 #define dout_subsys ceph_subsys_rgw
17
18
19 #define SWIFT_PERM_READ RGW_PERM_READ_OBJS
20 #define SWIFT_PERM_WRITE RGW_PERM_WRITE_OBJS
21 /* FIXME: do we really need separate RW? */
22 #define SWIFT_PERM_RWRT (SWIFT_PERM_READ | SWIFT_PERM_WRITE)
23 #define SWIFT_PERM_ADMIN RGW_PERM_FULL_CONTROL
24
25 #define SWIFT_GROUP_ALL_USERS ".r:*"
26
27 using namespace std;
28
29 static int parse_list(const char* uid_list,
30 std::vector<std::string>& uids) /* out */
31 {
32 char *s = strdup(uid_list);
33 if (!s) {
34 return -ENOMEM;
35 }
36
37 char *tokctx;
38 const char *p = strtok_r(s, " ,", &tokctx);
39 while (p) {
40 if (*p) {
41 string acl = p;
42 uids.push_back(acl);
43 }
44 p = strtok_r(NULL, " ,", &tokctx);
45 }
46 free(s);
47 return 0;
48 }
49
50 static bool is_referrer(const std::string& designator)
51 {
52 return designator.compare(".r") == 0 ||
53 designator.compare(".ref") == 0 ||
54 designator.compare(".referer") == 0 ||
55 designator.compare(".referrer") == 0;
56 }
57
58 static bool uid_is_public(const string& uid)
59 {
60 if (uid[0] != '.' || uid[1] != 'r')
61 return false;
62
63 int pos = uid.find(':');
64 if (pos < 0 || pos == (int)uid.size())
65 return false;
66
67 string sub = uid.substr(0, pos);
68 string after = uid.substr(pos + 1);
69
70 if (after.compare("*") != 0)
71 return false;
72
73 return is_referrer(sub);
74 }
75
76 static boost::optional<ACLGrant> referrer_to_grant(std::string url_spec,
77 const uint32_t perm)
78 {
79 /* This function takes url_spec as non-ref std::string because of the trim
80 * operation that is essential to preserve compliance with Swift. It can't
81 * be easily accomplished with std::string_view. */
82 try {
83 bool is_negative;
84 ACLGrant grant;
85
86 if ('-' == url_spec[0]) {
87 url_spec = url_spec.substr(1);
88 boost::algorithm::trim(url_spec);
89
90 is_negative = true;
91 } else {
92 is_negative = false;
93 }
94
95 if (url_spec != RGW_REFERER_WILDCARD) {
96 if ('*' == url_spec[0]) {
97 url_spec = url_spec.substr(1);
98 boost::algorithm::trim(url_spec);
99 }
100
101 if (url_spec.empty() || url_spec == ".") {
102 return boost::none;
103 }
104 } else {
105 /* Please be aware we're specially handling the .r:* in _add_grant()
106 * of RGWAccessControlList as the S3 API has a similar concept, and
107 * thus we can have a small portion of compatibility. */
108 }
109
110 grant.set_referer(url_spec, is_negative ? 0 : perm);
111 return grant;
112 } catch (const std::out_of_range&) {
113 return boost::none;
114 }
115 }
116
117 static ACLGrant user_to_grant(const DoutPrefixProvider *dpp,
118 CephContext* const cct,
119 rgw::sal::Driver* driver,
120 const std::string& uid,
121 const uint32_t perm)
122 {
123 RGWUserInfo grant_user;
124 ACLGrant grant;
125 std::unique_ptr<rgw::sal::User> user;
126
127 user = driver->get_user(rgw_user(uid));
128 if (user->load_user(dpp, null_yield) < 0) {
129 ldpp_dout(dpp, 10) << "grant user does not exist: " << uid << dendl;
130 /* skipping silently */
131 grant.set_canon(user->get_id(), std::string(), perm);
132 } else {
133 grant.set_canon(user->get_id(), user->get_display_name(), perm);
134 }
135
136 return grant;
137 }
138
139 int RGWAccessControlPolicy_SWIFT::add_grants(const DoutPrefixProvider *dpp,
140 rgw::sal::Driver* driver,
141 const std::vector<std::string>& uids,
142 const uint32_t perm)
143 {
144 for (const auto& uid : uids) {
145 boost::optional<ACLGrant> grant;
146 ldpp_dout(dpp, 20) << "trying to add grant for ACL uid=" << uid << dendl;
147
148 /* Let's check whether the item has a separator potentially indicating
149 * a special meaning (like an HTTP referral-based grant). */
150 const size_t pos = uid.find(':');
151 if (std::string::npos == pos) {
152 /* No, it don't have -- we've got just a regular user identifier. */
153 grant = user_to_grant(dpp, cct, driver, uid, perm);
154 } else {
155 /* Yes, *potentially* an HTTP referral. */
156 auto designator = uid.substr(0, pos);
157 auto designatee = uid.substr(pos + 1);
158
159 /* Swift strips whitespaces at both beginning and end. */
160 boost::algorithm::trim(designator);
161 boost::algorithm::trim(designatee);
162
163 if (! boost::algorithm::starts_with(designator, ".")) {
164 grant = user_to_grant(dpp, cct, driver, uid, perm);
165 } else if ((perm & SWIFT_PERM_WRITE) == 0 && is_referrer(designator)) {
166 /* HTTP referrer-based ACLs aren't acceptable for writes. */
167 grant = referrer_to_grant(designatee, perm);
168 }
169 }
170
171 if (grant) {
172 acl.add_grant(&*grant);
173 } else {
174 return -EINVAL;
175 }
176 }
177
178 return 0;
179 }
180
181
182 int RGWAccessControlPolicy_SWIFT::create(const DoutPrefixProvider *dpp,
183 rgw::sal::Driver* driver,
184 const rgw_user& id,
185 const std::string& name,
186 const char* read_list,
187 const char* write_list,
188 uint32_t& rw_mask)
189 {
190 acl.create_default(id, name);
191 owner.set_id(id);
192 owner.set_name(name);
193 rw_mask = 0;
194
195 if (read_list) {
196 std::vector<std::string> uids;
197 int r = parse_list(read_list, uids);
198 if (r < 0) {
199 ldpp_dout(dpp, 0) << "ERROR: parse_list for read returned r="
200 << r << dendl;
201 return r;
202 }
203
204 r = add_grants(dpp, driver, uids, SWIFT_PERM_READ);
205 if (r < 0) {
206 ldpp_dout(dpp, 0) << "ERROR: add_grants for read returned r="
207 << r << dendl;
208 return r;
209 }
210 rw_mask |= SWIFT_PERM_READ;
211 }
212 if (write_list) {
213 std::vector<std::string> uids;
214 int r = parse_list(write_list, uids);
215 if (r < 0) {
216 ldpp_dout(dpp, 0) << "ERROR: parse_list for write returned r="
217 << r << dendl;
218 return r;
219 }
220
221 r = add_grants(dpp, driver, uids, SWIFT_PERM_WRITE);
222 if (r < 0) {
223 ldpp_dout(dpp, 0) << "ERROR: add_grants for write returned r="
224 << r << dendl;
225 return r;
226 }
227 rw_mask |= SWIFT_PERM_WRITE;
228 }
229 return 0;
230 }
231
232 void RGWAccessControlPolicy_SWIFT::filter_merge(uint32_t rw_mask,
233 RGWAccessControlPolicy_SWIFT *old)
234 {
235 /* rw_mask&SWIFT_PERM_READ => setting read acl,
236 * rw_mask&SWIFT_PERM_WRITE => setting write acl
237 * when bit is cleared, copy matching elements from old.
238 */
239 if (rw_mask == (SWIFT_PERM_READ|SWIFT_PERM_WRITE)) {
240 return;
241 }
242 rw_mask ^= (SWIFT_PERM_READ|SWIFT_PERM_WRITE);
243 for (auto &iter: old->acl.get_grant_map()) {
244 ACLGrant& grant = iter.second;
245 uint32_t perm = grant.get_permission().get_permissions();
246 rgw_user id;
247 string url_spec;
248 if (!grant.get_id(id)) {
249 if (grant.get_group() != ACL_GROUP_ALL_USERS) {
250 url_spec = grant.get_referer();
251 if (url_spec.empty()) {
252 continue;
253 }
254 if (perm == 0) {
255 /* We need to carry also negative, HTTP referrer-based ACLs. */
256 perm = SWIFT_PERM_READ;
257 }
258 }
259 }
260 if (perm & rw_mask) {
261 acl.add_grant(&grant);
262 }
263 }
264 }
265
266 void RGWAccessControlPolicy_SWIFT::to_str(string& read, string& write)
267 {
268 multimap<string, ACLGrant>& m = acl.get_grant_map();
269 multimap<string, ACLGrant>::iterator iter;
270
271 for (iter = m.begin(); iter != m.end(); ++iter) {
272 ACLGrant& grant = iter->second;
273 const uint32_t perm = grant.get_permission().get_permissions();
274 rgw_user id;
275 string url_spec;
276 if (!grant.get_id(id)) {
277 if (grant.get_group() == ACL_GROUP_ALL_USERS) {
278 id = SWIFT_GROUP_ALL_USERS;
279 } else {
280 url_spec = grant.get_referer();
281 if (url_spec.empty()) {
282 continue;
283 }
284 id = (perm != 0) ? ".r:" + url_spec : ".r:-" + url_spec;
285 }
286 }
287 if (perm & SWIFT_PERM_READ) {
288 if (!read.empty()) {
289 read.append(",");
290 }
291 read.append(id.to_str());
292 } else if (perm & SWIFT_PERM_WRITE) {
293 if (!write.empty()) {
294 write.append(",");
295 }
296 write.append(id.to_str());
297 } else if (perm == 0 && !url_spec.empty()) {
298 /* only X-Container-Read headers support referers */
299 if (!read.empty()) {
300 read.append(",");
301 }
302 read.append(id.to_str());
303 }
304 }
305 }
306
307 void RGWAccessControlPolicy_SWIFTAcct::add_grants(const DoutPrefixProvider *dpp,
308 rgw::sal::Driver* driver,
309 const std::vector<std::string>& uids,
310 const uint32_t perm)
311 {
312 for (const auto& uid : uids) {
313 ACLGrant grant;
314
315 if (uid_is_public(uid)) {
316 grant.set_group(ACL_GROUP_ALL_USERS, perm);
317 acl.add_grant(&grant);
318 } else {
319 std::unique_ptr<rgw::sal::User> user = driver->get_user(rgw_user(uid));
320
321 if (user->load_user(dpp, null_yield) < 0) {
322 ldpp_dout(dpp, 10) << "grant user does not exist:" << uid << dendl;
323 /* skipping silently */
324 grant.set_canon(user->get_id(), std::string(), perm);
325 acl.add_grant(&grant);
326 } else {
327 grant.set_canon(user->get_id(), user->get_display_name(), perm);
328 acl.add_grant(&grant);
329 }
330 }
331 }
332 }
333
334 bool RGWAccessControlPolicy_SWIFTAcct::create(const DoutPrefixProvider *dpp,
335 rgw::sal::Driver* driver,
336 const rgw_user& id,
337 const std::string& name,
338 const std::string& acl_str)
339 {
340 acl.create_default(id, name);
341 owner.set_id(id);
342 owner.set_name(name);
343
344 JSONParser parser;
345
346 if (!parser.parse(acl_str.c_str(), acl_str.length())) {
347 ldpp_dout(dpp, 0) << "ERROR: JSONParser::parse returned error=" << dendl;
348 return false;
349 }
350
351 JSONObjIter iter = parser.find_first("admin");
352 if (!iter.end() && (*iter)->is_array()) {
353 std::vector<std::string> admin;
354 decode_json_obj(admin, *iter);
355 ldpp_dout(dpp, 0) << "admins: " << admin << dendl;
356
357 add_grants(dpp, driver, admin, SWIFT_PERM_ADMIN);
358 }
359
360 iter = parser.find_first("read-write");
361 if (!iter.end() && (*iter)->is_array()) {
362 std::vector<std::string> readwrite;
363 decode_json_obj(readwrite, *iter);
364 ldpp_dout(dpp, 0) << "read-write: " << readwrite << dendl;
365
366 add_grants(dpp, driver, readwrite, SWIFT_PERM_RWRT);
367 }
368
369 iter = parser.find_first("read-only");
370 if (!iter.end() && (*iter)->is_array()) {
371 std::vector<std::string> readonly;
372 decode_json_obj(readonly, *iter);
373 ldpp_dout(dpp, 0) << "read-only: " << readonly << dendl;
374
375 add_grants(dpp, driver, readonly, SWIFT_PERM_READ);
376 }
377
378 return true;
379 }
380
381 boost::optional<std::string> RGWAccessControlPolicy_SWIFTAcct::to_str() const
382 {
383 std::vector<std::string> admin;
384 std::vector<std::string> readwrite;
385 std::vector<std::string> readonly;
386
387 /* Parition the grant map into three not-overlapping groups. */
388 for (const auto& item : get_acl().get_grant_map()) {
389 const ACLGrant& grant = item.second;
390 const uint32_t perm = grant.get_permission().get_permissions();
391
392 rgw_user id;
393 if (!grant.get_id(id)) {
394 if (grant.get_group() != ACL_GROUP_ALL_USERS) {
395 continue;
396 }
397 id = SWIFT_GROUP_ALL_USERS;
398 } else if (owner.get_id() == id) {
399 continue;
400 }
401
402 if (SWIFT_PERM_ADMIN == (perm & SWIFT_PERM_ADMIN)) {
403 admin.insert(admin.end(), id.to_str());
404 } else if (SWIFT_PERM_RWRT == (perm & SWIFT_PERM_RWRT)) {
405 readwrite.insert(readwrite.end(), id.to_str());
406 } else if (SWIFT_PERM_READ == (perm & SWIFT_PERM_READ)) {
407 readonly.insert(readonly.end(), id.to_str());
408 } else {
409 // FIXME: print a warning
410 }
411 }
412
413 /* If there is no grant to serialize, let's exit earlier to not return
414 * an empty JSON object which brakes the functional tests of Swift. */
415 if (admin.empty() && readwrite.empty() && readonly.empty()) {
416 return boost::none;
417 }
418
419 /* Serialize the groups. */
420 JSONFormatter formatter;
421
422 formatter.open_object_section("acl");
423 if (!readonly.empty()) {
424 encode_json("read-only", readonly, &formatter);
425 }
426 if (!readwrite.empty()) {
427 encode_json("read-write", readwrite, &formatter);
428 }
429 if (!admin.empty()) {
430 encode_json("admin", admin, &formatter);
431 }
432 formatter.close_section();
433
434 std::ostringstream oss;
435 formatter.flush(oss);
436
437 return oss.str();
438 }