Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / rgw / rgw_role.cc
1 #include <errno.h>
2 #include <ctime>
3
4 #include <boost/regex.hpp>
5
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
43   string oid = tenant + get_names_oid_prefix() + name;
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 {
53   string oid = tenant + get_path_oid_prefix() + path + get_info_oid_prefix() + id;
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
63   if (! validate_input()) {
64     return -EINVAL;
65   }
66
67   /* check to see the name is not used */
68   ret = read_id(name, tenant, id);
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
87   arn = role_arn_prefix + tenant + ":role" + path + name;
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
137     oid = tenant + get_names_oid_prefix() + name;
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
175   oid = tenant + get_names_oid_prefix() + name;
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
183   oid = tenant + get_path_oid_prefix() + path + get_info_oid_prefix() + id;
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
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
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
291 int RGWRole::read_id(const string& role_name, const string& tenant, string& role_id)
292 {
293   auto& pool = store->get_zone_params().roles_pool;
294   string oid = tenant + get_names_oid_prefix() + role_name;
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;
345   string oid = tenant + get_names_oid_prefix() + name;
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
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
405 void RGWRole::update_trust_policy(string& trust_policy)
406 {
407   this->trust_policy = trust_policy;
408 }
409
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)
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()) {
421     prefix = tenant + role_path_oid_prefix + path_prefix;
422   } else {
423     prefix = tenant + role_path_oid_prefix;
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 }