]> git.proxmox.com Git - ceph.git/blame - ceph/src/rgw/rgw_acl_swift.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / rgw / rgw_acl_swift.cc
CommitLineData
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#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"
20effc67 14#include "rgw_sal.h"
7c673cae
FG
15
16#define dout_subsys ceph_subsys_rgw
17
7c673cae
FG
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
20effc67
TL
27using namespace std;
28
28e407b8 29static int parse_list(const char* uid_list,
7c673cae
FG
30 std::vector<std::string>& uids) /* out */
31{
28e407b8 32 char *s = strdup(uid_list);
7c673cae
FG
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
50static 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
58static 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
76static 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
f67539c2 81 * be easily accomplished with std::string_view. */
7c673cae
FG
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
31f18b77 95 if (url_spec != RGW_REFERER_WILDCARD) {
7c673cae
FG
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 }
31f18b77
FG
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. */
7c673cae
FG
108 }
109
31f18b77 110 grant.set_referer(url_spec, is_negative ? 0 : perm);
7c673cae 111 return grant;
11fdf7f2 112 } catch (const std::out_of_range&) {
7c673cae
FG
113 return boost::none;
114 }
115}
116
20effc67
TL
117static ACLGrant user_to_grant(const DoutPrefixProvider *dpp,
118 CephContext* const cct,
1e59de90 119 rgw::sal::Driver* driver,
7c673cae
FG
120 const std::string& uid,
121 const uint32_t perm)
122{
7c673cae
FG
123 RGWUserInfo grant_user;
124 ACLGrant grant;
20effc67 125 std::unique_ptr<rgw::sal::User> user;
7c673cae 126
1e59de90 127 user = driver->get_user(rgw_user(uid));
20effc67
TL
128 if (user->load_user(dpp, null_yield) < 0) {
129 ldpp_dout(dpp, 10) << "grant user does not exist: " << uid << dendl;
7c673cae 130 /* skipping silently */
20effc67 131 grant.set_canon(user->get_id(), std::string(), perm);
7c673cae 132 } else {
20effc67 133 grant.set_canon(user->get_id(), user->get_display_name(), perm);
7c673cae
FG
134 }
135
136 return grant;
137}
138
20effc67 139int RGWAccessControlPolicy_SWIFT::add_grants(const DoutPrefixProvider *dpp,
1e59de90 140 rgw::sal::Driver* driver,
7c673cae
FG
141 const std::vector<std::string>& uids,
142 const uint32_t perm)
143{
144 for (const auto& uid : uids) {
145 boost::optional<ACLGrant> grant;
b3b6e05e 146 ldpp_dout(dpp, 20) << "trying to add grant for ACL uid=" << uid << dendl;
7c673cae
FG
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. */
1e59de90 153 grant = user_to_grant(dpp, cct, driver, uid, perm);
7c673cae
FG
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, ".")) {
1e59de90 164 grant = user_to_grant(dpp, cct, driver, uid, perm);
7c673cae
FG
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
20effc67 182int RGWAccessControlPolicy_SWIFT::create(const DoutPrefixProvider *dpp,
1e59de90 183 rgw::sal::Driver* driver,
7c673cae
FG
184 const rgw_user& id,
185 const std::string& name,
28e407b8
AA
186 const char* read_list,
187 const char* write_list,
7c673cae
FG
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
28e407b8 195 if (read_list) {
7c673cae
FG
196 std::vector<std::string> uids;
197 int r = parse_list(read_list, uids);
198 if (r < 0) {
b3b6e05e 199 ldpp_dout(dpp, 0) << "ERROR: parse_list for read returned r="
7c673cae
FG
200 << r << dendl;
201 return r;
202 }
203
1e59de90 204 r = add_grants(dpp, driver, uids, SWIFT_PERM_READ);
7c673cae 205 if (r < 0) {
20effc67 206 ldpp_dout(dpp, 0) << "ERROR: add_grants for read returned r="
7c673cae
FG
207 << r << dendl;
208 return r;
209 }
210 rw_mask |= SWIFT_PERM_READ;
211 }
28e407b8 212 if (write_list) {
7c673cae
FG
213 std::vector<std::string> uids;
214 int r = parse_list(write_list, uids);
215 if (r < 0) {
b3b6e05e 216 ldpp_dout(dpp, 0) << "ERROR: parse_list for write returned r="
7c673cae
FG
217 << r << dendl;
218 return r;
219 }
220
1e59de90 221 r = add_grants(dpp, driver, uids, SWIFT_PERM_WRITE);
7c673cae 222 if (r < 0) {
20effc67 223 ldpp_dout(dpp, 0) << "ERROR: add_grants for write returned r="
7c673cae
FG
224 << r << dendl;
225 return r;
226 }
227 rw_mask |= SWIFT_PERM_WRITE;
228 }
229 return 0;
230}
231
232void 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
266void 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
20effc67 307void RGWAccessControlPolicy_SWIFTAcct::add_grants(const DoutPrefixProvider *dpp,
1e59de90 308 rgw::sal::Driver* driver,
7c673cae
FG
309 const std::vector<std::string>& uids,
310 const uint32_t perm)
311{
312 for (const auto& uid : uids) {
313 ACLGrant grant;
7c673cae
FG
314
315 if (uid_is_public(uid)) {
316 grant.set_group(ACL_GROUP_ALL_USERS, perm);
317 acl.add_grant(&grant);
318 } else {
1e59de90 319 std::unique_ptr<rgw::sal::User> user = driver->get_user(rgw_user(uid));
7c673cae 320
20effc67
TL
321 if (user->load_user(dpp, null_yield) < 0) {
322 ldpp_dout(dpp, 10) << "grant user does not exist:" << uid << dendl;
7c673cae 323 /* skipping silently */
20effc67 324 grant.set_canon(user->get_id(), std::string(), perm);
7c673cae
FG
325 acl.add_grant(&grant);
326 } else {
20effc67 327 grant.set_canon(user->get_id(), user->get_display_name(), perm);
7c673cae
FG
328 acl.add_grant(&grant);
329 }
330 }
331 }
332}
333
20effc67 334bool RGWAccessControlPolicy_SWIFTAcct::create(const DoutPrefixProvider *dpp,
1e59de90 335 rgw::sal::Driver* driver,
7c673cae
FG
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())) {
b3b6e05e 347 ldpp_dout(dpp, 0) << "ERROR: JSONParser::parse returned error=" << dendl;
7c673cae
FG
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);
20effc67 355 ldpp_dout(dpp, 0) << "admins: " << admin << dendl;
7c673cae 356
1e59de90 357 add_grants(dpp, driver, admin, SWIFT_PERM_ADMIN);
7c673cae
FG
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);
20effc67 364 ldpp_dout(dpp, 0) << "read-write: " << readwrite << dendl;
7c673cae 365
1e59de90 366 add_grants(dpp, driver, readwrite, SWIFT_PERM_RWRT);
7c673cae
FG
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);
20effc67 373 ldpp_dout(dpp, 0) << "read-only: " << readonly << dendl;
7c673cae 374
1e59de90 375 add_grants(dpp, driver, readonly, SWIFT_PERM_READ);
7c673cae
FG
376 }
377
378 return true;
379}
380
224ce89b 381boost::optional<std::string> RGWAccessControlPolicy_SWIFTAcct::to_str() const
7c673cae
FG
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
224ce89b
WB
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
7c673cae
FG
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
224ce89b 437 return oss.str();
7c673cae 438}