]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | #include <errno.h> |
2 | #include <ctime> | |
3 | ||
31f18b77 FG |
4 | #include <boost/regex.hpp> |
5 | ||
7c673cae FG |
6 | #include "common/errno.h" |
7 | #include "common/Formatter.h" | |
8 | #include "common/ceph_json.h" | |
9 | #include "common/ceph_time.h" | |
10 | #include "rgw_rados.h" | |
11 | ||
12 | #include "include/types.h" | |
13 | #include "rgw_string.h" | |
14 | ||
15 | #include "rgw_common.h" | |
16 | #include "rgw_tools.h" | |
17 | #include "rgw_role.h" | |
18 | ||
19 | #define dout_subsys ceph_subsys_rgw | |
20 | ||
21 | using namespace std; | |
22 | ||
23 | const string RGWRole::role_name_oid_prefix = "role_names."; | |
24 | const string RGWRole::role_oid_prefix = "roles."; | |
25 | const string RGWRole::role_path_oid_prefix = "role_paths."; | |
26 | const string RGWRole::role_arn_prefix = "arn:aws:iam::"; | |
27 | ||
28 | int RGWRole::store_info(bool exclusive) | |
29 | { | |
30 | string oid = get_info_oid_prefix() + id; | |
31 | ||
32 | bufferlist bl; | |
33 | ::encode(*this, bl); | |
34 | return rgw_put_system_obj(store, store->get_zone_params().roles_pool, oid, | |
35 | bl.c_str(), bl.length(), exclusive, NULL, real_time(), NULL); | |
36 | } | |
37 | ||
38 | int RGWRole::store_name(bool exclusive) | |
39 | { | |
40 | RGWNameToId nameToId; | |
41 | nameToId.obj_id = id; | |
42 | ||
31f18b77 | 43 | string oid = tenant + get_names_oid_prefix() + name; |
7c673cae FG |
44 | |
45 | bufferlist bl; | |
46 | ::encode(nameToId, bl); | |
47 | return rgw_put_system_obj(store, store->get_zone_params().roles_pool, oid, | |
48 | bl.c_str(), bl.length(), exclusive, NULL, real_time(), NULL); | |
49 | } | |
50 | ||
51 | int RGWRole::store_path(bool exclusive) | |
52 | { | |
31f18b77 | 53 | string oid = tenant + get_path_oid_prefix() + path + get_info_oid_prefix() + id; |
7c673cae FG |
54 | |
55 | return rgw_put_system_obj(store, store->get_zone_params().roles_pool, oid, | |
56 | NULL, 0, exclusive, NULL, real_time(), NULL); | |
57 | } | |
58 | ||
59 | int RGWRole::create(bool exclusive) | |
60 | { | |
61 | int ret; | |
62 | ||
31f18b77 FG |
63 | if (! validate_input()) { |
64 | return -EINVAL; | |
65 | } | |
66 | ||
7c673cae | 67 | /* check to see the name is not used */ |
31f18b77 | 68 | ret = read_id(name, tenant, id); |
7c673cae FG |
69 | if (exclusive && ret == 0) { |
70 | ldout(cct, 0) << "ERROR: name " << name << " already in use for role id " | |
71 | << id << dendl; | |
72 | return -EEXIST; | |
73 | } else if ( ret < 0 && ret != -ENOENT) { | |
74 | ldout(cct, 0) << "failed reading role id " << id << ": " | |
75 | << cpp_strerror(-ret) << dendl; | |
76 | return ret; | |
77 | } | |
78 | ||
79 | /* create unique id */ | |
80 | uuid_d new_uuid; | |
81 | char uuid_str[37]; | |
82 | new_uuid.generate_random(); | |
83 | new_uuid.print(uuid_str); | |
84 | id = uuid_str; | |
85 | ||
86 | //arn | |
31f18b77 | 87 | arn = role_arn_prefix + tenant + ":role" + path + name; |
7c673cae FG |
88 | |
89 | // Creation time | |
90 | real_clock::time_point t = real_clock::now(); | |
91 | ||
92 | struct timeval tv; | |
93 | real_clock::to_timeval(t, tv); | |
94 | ||
95 | char buf[30]; | |
96 | struct tm result; | |
97 | gmtime_r(&tv.tv_sec, &result); | |
98 | strftime(buf,30,"%Y-%m-%dT%H:%M:%S", &result); | |
99 | sprintf(buf + strlen(buf),".%dZ",(int)tv.tv_usec/1000); | |
100 | creation_date.assign(buf, strlen(buf)); | |
101 | ||
102 | auto& pool = store->get_zone_params().roles_pool; | |
103 | ret = store_info(exclusive); | |
104 | if (ret < 0) { | |
105 | ldout(cct, 0) << "ERROR: storing role info in pool: " << pool.name << ": " | |
106 | << id << ": " << cpp_strerror(-ret) << dendl; | |
107 | return ret; | |
108 | } | |
109 | ||
110 | ret = store_name(exclusive); | |
111 | if (ret < 0) { | |
112 | ldout(cct, 0) << "ERROR: storing role name in pool: " << pool.name << ": " | |
113 | << name << ": " << cpp_strerror(-ret) << dendl; | |
114 | ||
115 | //Delete the role info that was stored in the previous call | |
116 | string oid = get_info_oid_prefix() + id; | |
117 | int info_ret = rgw_delete_system_obj(store, pool, oid, NULL); | |
118 | if (info_ret < 0) { | |
119 | ldout(cct, 0) << "ERROR: cleanup of role id from pool: " << pool.name << ": " | |
120 | << id << ": " << cpp_strerror(-info_ret) << dendl; | |
121 | } | |
122 | return ret; | |
123 | } | |
124 | ||
125 | ret = store_path(exclusive); | |
126 | if (ret < 0) { | |
127 | ldout(cct, 0) << "ERROR: storing role path in pool: " << pool.name << ": " | |
128 | << path << ": " << cpp_strerror(-ret) << dendl; | |
129 | //Delete the role info that was stored in the previous call | |
130 | string oid = get_info_oid_prefix() + id; | |
131 | int info_ret = rgw_delete_system_obj(store, pool, oid, NULL); | |
132 | if (info_ret < 0) { | |
133 | ldout(cct, 0) << "ERROR: cleanup of role id from pool: " << pool.name << ": " | |
134 | << id << ": " << cpp_strerror(-info_ret) << dendl; | |
135 | } | |
136 | //Delete role name that was stored in previous call | |
31f18b77 | 137 | oid = tenant + get_names_oid_prefix() + name; |
7c673cae FG |
138 | int name_ret = rgw_delete_system_obj(store, pool, oid, NULL); |
139 | if (name_ret < 0) { | |
140 | ldout(cct, 0) << "ERROR: cleanup of role name from pool: " << pool.name << ": " | |
141 | << name << ": " << cpp_strerror(-name_ret) << dendl; | |
142 | } | |
143 | return ret; | |
144 | } | |
145 | return 0; | |
146 | } | |
147 | ||
148 | int RGWRole::delete_obj() | |
149 | { | |
150 | auto& pool = store->get_zone_params().roles_pool; | |
151 | ||
152 | int ret = read_name(); | |
153 | if (ret < 0) { | |
154 | return ret; | |
155 | } | |
156 | ||
157 | ret = read_info(); | |
158 | if (ret < 0) { | |
159 | return ret; | |
160 | } | |
161 | ||
162 | if (! perm_policy_map.empty()) { | |
163 | return -ERR_DELETE_CONFLICT; | |
164 | } | |
165 | ||
166 | // Delete id | |
167 | string oid = get_info_oid_prefix() + id; | |
168 | ret = rgw_delete_system_obj(store, pool, oid, NULL); | |
169 | if (ret < 0) { | |
170 | ldout(cct, 0) << "ERROR: deleting role id from pool: " << pool.name << ": " | |
171 | << id << ": " << cpp_strerror(-ret) << dendl; | |
172 | } | |
173 | ||
174 | // Delete name | |
31f18b77 | 175 | oid = tenant + get_names_oid_prefix() + name; |
7c673cae FG |
176 | ret = rgw_delete_system_obj(store, pool, oid, NULL); |
177 | if (ret < 0) { | |
178 | ldout(cct, 0) << "ERROR: deleting role name from pool: " << pool.name << ": " | |
179 | << name << ": " << cpp_strerror(-ret) << dendl; | |
180 | } | |
181 | ||
182 | // Delete path | |
31f18b77 | 183 | oid = tenant + get_path_oid_prefix() + path + get_info_oid_prefix() + id; |
7c673cae FG |
184 | ret = rgw_delete_system_obj(store, pool, oid, NULL); |
185 | if (ret < 0) { | |
186 | ldout(cct, 0) << "ERROR: deleting role path from pool: " << pool.name << ": " | |
187 | << path << ": " << cpp_strerror(-ret) << dendl; | |
188 | } | |
189 | return ret; | |
190 | } | |
191 | ||
192 | int RGWRole::get() | |
193 | { | |
194 | int ret = read_name(); | |
195 | if (ret < 0) { | |
196 | return ret; | |
197 | } | |
198 | ||
199 | ret = read_info(); | |
200 | if (ret < 0) { | |
201 | return ret; | |
202 | } | |
203 | ||
204 | return 0; | |
205 | } | |
206 | ||
31f18b77 FG |
207 | int RGWRole::get_by_id() |
208 | { | |
209 | int ret = read_info(); | |
210 | if (ret < 0) { | |
211 | return ret; | |
212 | } | |
213 | ||
214 | return 0; | |
215 | } | |
216 | ||
7c673cae FG |
217 | int RGWRole::update() |
218 | { | |
219 | auto& pool = store->get_zone_params().roles_pool; | |
220 | ||
221 | int ret = store_info(false); | |
222 | if (ret < 0) { | |
223 | ldout(cct, 0) << "ERROR: storing info in pool: " << pool.name << ": " | |
224 | << id << ": " << cpp_strerror(-ret) << dendl; | |
225 | return ret; | |
226 | } | |
227 | ||
228 | return 0; | |
229 | } | |
230 | ||
231 | void RGWRole::set_perm_policy(const string& policy_name, const string& perm_policy) | |
232 | { | |
233 | perm_policy_map[policy_name] = perm_policy; | |
234 | } | |
235 | ||
236 | vector<string> RGWRole::get_role_policy_names() | |
237 | { | |
238 | vector<string> policy_names; | |
239 | for (const auto& it : perm_policy_map) | |
240 | { | |
241 | policy_names.push_back(std::move(it.first)); | |
242 | } | |
243 | ||
244 | return policy_names; | |
245 | } | |
246 | ||
247 | int RGWRole::get_role_policy(const string& policy_name, string& perm_policy) | |
248 | { | |
249 | const auto it = perm_policy_map.find(policy_name); | |
250 | if (it == perm_policy_map.end()) { | |
251 | ldout(cct, 0) << "ERROR: Policy name: " << policy_name << " not found" << dendl; | |
252 | return -EINVAL; | |
253 | } else { | |
254 | perm_policy = it->second; | |
255 | } | |
256 | return 0; | |
257 | } | |
258 | ||
259 | int RGWRole::delete_policy(const string& policy_name) | |
260 | { | |
261 | const auto& it = perm_policy_map.find(policy_name); | |
262 | if (it == perm_policy_map.end()) { | |
263 | ldout(cct, 0) << "ERROR: Policy name: " << policy_name << " not found" << dendl; | |
264 | return -ENOENT; | |
265 | } else { | |
266 | perm_policy_map.erase(it); | |
267 | } | |
268 | return 0; | |
269 | } | |
270 | ||
271 | void RGWRole::dump(Formatter *f) const | |
272 | { | |
273 | encode_json("id", id , f); | |
274 | encode_json("name", name , f); | |
275 | encode_json("path", path, f); | |
276 | encode_json("arn", arn, f); | |
277 | encode_json("create_date", creation_date, f); | |
278 | encode_json("assume_role_policy_document", trust_policy, f); | |
279 | } | |
280 | ||
281 | void RGWRole::decode_json(JSONObj *obj) | |
282 | { | |
283 | JSONDecoder::decode_json("id", id, obj); | |
284 | JSONDecoder::decode_json("name", name, obj); | |
285 | JSONDecoder::decode_json("path", path, obj); | |
286 | JSONDecoder::decode_json("arn", arn, obj); | |
287 | JSONDecoder::decode_json("create_date", creation_date, obj); | |
288 | JSONDecoder::decode_json("assume_role_policy_document", trust_policy, obj); | |
289 | } | |
290 | ||
31f18b77 | 291 | int RGWRole::read_id(const string& role_name, const string& tenant, string& role_id) |
7c673cae FG |
292 | { |
293 | auto& pool = store->get_zone_params().roles_pool; | |
31f18b77 | 294 | string oid = tenant + get_names_oid_prefix() + role_name; |
7c673cae FG |
295 | bufferlist bl; |
296 | RGWObjectCtx obj_ctx(store); | |
297 | ||
298 | int ret = rgw_get_system_obj(store, obj_ctx, pool, oid, bl, NULL, NULL); | |
299 | if (ret < 0) { | |
300 | return ret; | |
301 | } | |
302 | ||
303 | RGWNameToId nameToId; | |
304 | try { | |
305 | bufferlist::iterator iter = bl.begin(); | |
306 | ::decode(nameToId, iter); | |
307 | } catch (buffer::error& err) { | |
308 | ldout(cct, 0) << "ERROR: failed to decode role from pool: " << pool.name << ": " | |
309 | << role_name << dendl; | |
310 | return -EIO; | |
311 | } | |
312 | role_id = nameToId.obj_id; | |
313 | return 0; | |
314 | } | |
315 | ||
316 | int RGWRole::read_info() | |
317 | { | |
318 | auto& pool = store->get_zone_params().roles_pool; | |
319 | string oid = get_info_oid_prefix() + id; | |
320 | bufferlist bl; | |
321 | RGWObjectCtx obj_ctx(store); | |
322 | ||
323 | int ret = rgw_get_system_obj(store, obj_ctx, pool, oid, bl, NULL, NULL); | |
324 | if (ret < 0) { | |
325 | ldout(cct, 0) << "ERROR: failed reading role info from pool: " << pool.name << | |
326 | ": " << id << ": " << cpp_strerror(-ret) << dendl; | |
327 | return ret; | |
328 | } | |
329 | ||
330 | try { | |
331 | bufferlist::iterator iter = bl.begin(); | |
332 | ::decode(*this, iter); | |
333 | } catch (buffer::error& err) { | |
334 | ldout(cct, 0) << "ERROR: failed to decode role info from pool: " << pool.name << | |
335 | ": " << id << dendl; | |
336 | return -EIO; | |
337 | } | |
338 | ||
339 | return 0; | |
340 | } | |
341 | ||
342 | int RGWRole::read_name() | |
343 | { | |
344 | auto& pool = store->get_zone_params().roles_pool; | |
31f18b77 | 345 | string oid = tenant + get_names_oid_prefix() + name; |
7c673cae FG |
346 | bufferlist bl; |
347 | RGWObjectCtx obj_ctx(store); | |
348 | ||
349 | int ret = rgw_get_system_obj(store, obj_ctx, pool, oid, bl, NULL, NULL); | |
350 | if (ret < 0) { | |
351 | ldout(cct, 0) << "ERROR: failed reading role name from pool: " << pool.name << ": " | |
352 | << name << ": " << cpp_strerror(-ret) << dendl; | |
353 | return ret; | |
354 | } | |
355 | ||
356 | RGWNameToId nameToId; | |
357 | try { | |
358 | bufferlist::iterator iter = bl.begin(); | |
359 | ::decode(nameToId, iter); | |
360 | } catch (buffer::error& err) { | |
361 | ldout(cct, 0) << "ERROR: failed to decode role name from pool: " << pool.name << ": " | |
362 | << name << dendl; | |
363 | return -EIO; | |
364 | } | |
365 | id = nameToId.obj_id; | |
366 | return 0; | |
367 | } | |
368 | ||
31f18b77 FG |
369 | bool RGWRole::validate_input() |
370 | { | |
371 | if (name.length() > MAX_ROLE_NAME_LEN) { | |
372 | ldout(cct, 0) << "ERROR: Invalid name length " << dendl; | |
373 | return false; | |
374 | } | |
375 | ||
376 | if (path.length() > MAX_PATH_NAME_LEN) { | |
377 | ldout(cct, 0) << "ERROR: Invalid path length " << dendl; | |
378 | return false; | |
379 | } | |
380 | ||
381 | boost::regex regex_name("[A-Za-z0-9:=,.@-]+"); | |
382 | if (! boost::regex_match(name, regex_name)) { | |
383 | ldout(cct, 0) << "ERROR: Invalid chars in name " << dendl; | |
384 | return false; | |
385 | } | |
386 | ||
387 | boost::regex regex_path("(/[!-~]+/)|(/)"); | |
388 | if (! boost::regex_match(path,regex_path)) { | |
389 | ldout(cct, 0) << "ERROR: Invalid chars in path " << dendl; | |
390 | return false; | |
391 | } | |
392 | ||
393 | return true; | |
394 | } | |
395 | ||
396 | void RGWRole::extract_name_tenant(const std::string& str) | |
397 | { | |
398 | size_t pos = str.find('$'); | |
399 | if (pos != std::string::npos) { | |
400 | tenant = str.substr(0, pos); | |
401 | name = str.substr(pos + 1); | |
402 | } | |
403 | } | |
404 | ||
7c673cae FG |
405 | void RGWRole::update_trust_policy(string& trust_policy) |
406 | { | |
407 | this->trust_policy = trust_policy; | |
408 | } | |
409 | ||
31f18b77 FG |
410 | int RGWRole::get_roles_by_path_prefix(RGWRados *store, |
411 | CephContext *cct, | |
412 | const string& path_prefix, | |
413 | const string& tenant, | |
414 | vector<RGWRole>& roles) | |
7c673cae FG |
415 | { |
416 | auto pool = store->get_zone_params().roles_pool; | |
417 | string prefix; | |
418 | ||
419 | // List all roles if path prefix is empty | |
420 | if (! path_prefix.empty()) { | |
31f18b77 | 421 | prefix = tenant + role_path_oid_prefix + path_prefix; |
7c673cae | 422 | } else { |
31f18b77 | 423 | prefix = tenant + role_path_oid_prefix; |
7c673cae FG |
424 | } |
425 | ||
426 | //Get the filtered objects | |
427 | list<string> result; | |
428 | bool is_truncated; | |
429 | RGWListRawObjsCtx ctx; | |
430 | do { | |
431 | list<string> oids; | |
432 | int r = store->list_raw_objects(pool, prefix, 1000, ctx, oids, &is_truncated); | |
433 | if (r < 0) { | |
434 | ldout(cct, 0) << "ERROR: listing filtered objects failed: " << pool.name << ": " | |
435 | << prefix << ": " << cpp_strerror(-r) << dendl; | |
436 | return r; | |
437 | } | |
438 | for (const auto& iter : oids) { | |
439 | result.push_back(iter.substr(role_path_oid_prefix.size())); | |
440 | } | |
441 | } while (is_truncated); | |
442 | ||
443 | for (const auto& it : result) { | |
444 | //Find the role oid prefix from the end | |
445 | size_t pos = it.rfind(role_oid_prefix); | |
446 | if (pos == string::npos) { | |
447 | continue; | |
448 | } | |
449 | // Split the result into path and info_oid + id | |
450 | string path = it.substr(0, pos); | |
451 | ||
452 | /*Make sure that prefix is part of path (False results could've been returned) | |
453 | because of the role info oid + id appended to the path)*/ | |
454 | if(path_prefix.empty() || path.find(path_prefix) != string::npos) { | |
455 | //Get id from info oid prefix + id | |
456 | string id = it.substr(pos + role_oid_prefix.length()); | |
457 | ||
458 | RGWRole role(cct, store); | |
459 | role.set_id(id); | |
460 | int ret = role.read_info(); | |
461 | if (ret < 0) { | |
462 | return ret; | |
463 | } | |
464 | roles.push_back(std::move(role)); | |
465 | } | |
466 | } | |
467 | ||
468 | return 0; | |
469 | } | |
470 | ||
471 | const string& RGWRole::get_names_oid_prefix() | |
472 | { | |
473 | return role_name_oid_prefix; | |
474 | } | |
475 | ||
476 | const string& RGWRole::get_info_oid_prefix() | |
477 | { | |
478 | return role_oid_prefix; | |
479 | } | |
480 | ||
481 | const string& RGWRole::get_path_oid_prefix() | |
482 | { | |
483 | return role_path_oid_prefix; | |
484 | } |