]>
Commit | Line | Data |
---|---|---|
11fdf7f2 | 1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
9f95a23c | 2 | // vim: ts=8 sw=2 smarttab ft=cpp |
11fdf7f2 | 3 | |
7c673cae FG |
4 | #include <errno.h> |
5 | #include <ctime> | |
11fdf7f2 | 6 | #include <regex> |
39ae355f | 7 | #include <boost/algorithm/string/replace.hpp> |
31f18b77 | 8 | |
7c673cae FG |
9 | #include "common/errno.h" |
10 | #include "common/Formatter.h" | |
11 | #include "common/ceph_json.h" | |
12 | #include "common/ceph_time.h" | |
13 | #include "rgw_rados.h" | |
11fdf7f2 | 14 | #include "rgw_zone.h" |
7c673cae FG |
15 | |
16 | #include "include/types.h" | |
17 | #include "rgw_string.h" | |
18 | ||
19 | #include "rgw_common.h" | |
20 | #include "rgw_tools.h" | |
21 | #include "rgw_role.h" | |
22 | ||
11fdf7f2 TL |
23 | #include "services/svc_zone.h" |
24 | #include "services/svc_sys_obj.h" | |
39ae355f TL |
25 | #include "services/svc_meta_be_sobj.h" |
26 | #include "services/svc_meta.h" | |
27 | #include "services/svc_role_rados.h" | |
11fdf7f2 | 28 | |
7c673cae FG |
29 | #define dout_subsys ceph_subsys_rgw |
30 | ||
20effc67 TL |
31 | using namespace std; |
32 | ||
33 | namespace rgw { namespace sal { | |
7c673cae FG |
34 | |
35 | const string RGWRole::role_name_oid_prefix = "role_names."; | |
36 | const string RGWRole::role_oid_prefix = "roles."; | |
37 | const string RGWRole::role_path_oid_prefix = "role_paths."; | |
38 | const string RGWRole::role_arn_prefix = "arn:aws:iam::"; | |
39 | ||
39ae355f TL |
40 | void RGWRoleInfo::dump(Formatter *f) const |
41 | { | |
42 | encode_json("RoleId", id , f); | |
43 | std::string role_name; | |
44 | if (tenant.empty()) { | |
45 | role_name = name; | |
46 | } else { | |
47 | role_name = tenant + '$' + name; | |
48 | } | |
49 | encode_json("RoleName", role_name , f); | |
50 | encode_json("Path", path, f); | |
51 | encode_json("Arn", arn, f); | |
52 | encode_json("CreateDate", creation_date, f); | |
53 | encode_json("MaxSessionDuration", max_session_duration, f); | |
54 | encode_json("AssumeRolePolicyDocument", trust_policy, f); | |
55 | if (!perm_policy_map.empty()) { | |
56 | f->open_array_section("PermissionPolicies"); | |
57 | for (const auto& it : perm_policy_map) { | |
58 | f->open_object_section("Policy"); | |
59 | encode_json("PolicyName", it.first, f); | |
60 | encode_json("PolicyValue", it.second, f); | |
61 | f->close_section(); | |
62 | } | |
63 | f->close_section(); | |
64 | } | |
65 | if (!tags.empty()) { | |
66 | f->open_array_section("Tags"); | |
67 | for (const auto& it : tags) { | |
68 | f->open_object_section("Tag"); | |
69 | encode_json("Key", it.first, f); | |
70 | encode_json("Value", it.second, f); | |
71 | f->close_section(); | |
72 | } | |
73 | f->close_section(); | |
74 | } | |
75 | } | |
76 | ||
77 | void RGWRoleInfo::decode_json(JSONObj *obj) | |
78 | { | |
79 | JSONDecoder::decode_json("RoleId", id, obj); | |
80 | JSONDecoder::decode_json("RoleName", name, obj); | |
81 | JSONDecoder::decode_json("Path", path, obj); | |
82 | JSONDecoder::decode_json("Arn", arn, obj); | |
83 | JSONDecoder::decode_json("CreateDate", creation_date, obj); | |
84 | JSONDecoder::decode_json("MaxSessionDuration", max_session_duration, obj); | |
85 | JSONDecoder::decode_json("AssumeRolePolicyDocument", trust_policy, obj); | |
86 | ||
87 | auto tags_iter = obj->find_first("Tags"); | |
88 | if (!tags_iter.end()) { | |
89 | JSONObj* tags_json = *tags_iter; | |
90 | auto iter = tags_json->find_first(); | |
91 | ||
92 | for (; !iter.end(); ++iter) { | |
93 | std::string key, val; | |
94 | JSONDecoder::decode_json("Key", key, *iter); | |
95 | JSONDecoder::decode_json("Value", val, *iter); | |
96 | this->tags.emplace(key, val); | |
97 | } | |
98 | } | |
99 | ||
100 | auto perm_policy_iter = obj->find_first("PermissionPolicies"); | |
101 | if (!perm_policy_iter.end()) { | |
102 | JSONObj* perm_policies = *perm_policy_iter; | |
103 | auto iter = perm_policies->find_first(); | |
104 | ||
105 | for (; !iter.end(); ++iter) { | |
106 | std::string policy_name, policy_val; | |
107 | JSONDecoder::decode_json("PolicyName", policy_name, *iter); | |
108 | JSONDecoder::decode_json("PolicyValue", policy_val, *iter); | |
109 | this->perm_policy_map.emplace(policy_name, policy_val); | |
110 | } | |
111 | } | |
112 | ||
113 | if (auto pos = name.find('$'); pos != std::string::npos) { | |
114 | tenant = name.substr(0, pos); | |
115 | name = name.substr(pos+1); | |
116 | } | |
117 | } | |
118 | ||
119 | RGWRole::RGWRole(std::string name, | |
120 | std::string tenant, | |
121 | std::string path, | |
122 | std::string trust_policy, | |
123 | std::string max_session_duration_str, | |
124 | std::multimap<std::string,std::string> tags) | |
125 | { | |
126 | info.name = std::move(name); | |
127 | info.path = std::move(path); | |
128 | info.trust_policy = std::move(trust_policy); | |
129 | info.tenant = std::move(tenant); | |
130 | info.tags = std::move(tags); | |
131 | if (this->info.path.empty()) | |
132 | this->info.path = "/"; | |
133 | extract_name_tenant(this->info.name); | |
134 | if (max_session_duration_str.empty()) { | |
135 | info.max_session_duration = SESSION_DURATION_MIN; | |
136 | } else { | |
137 | info.max_session_duration = std::stoull(max_session_duration_str); | |
138 | } | |
139 | info.mtime = real_time(); | |
140 | } | |
141 | ||
142 | RGWRole::RGWRole(std::string id) | |
143 | { | |
144 | info.id = std::move(id); | |
145 | } | |
146 | ||
b3b6e05e | 147 | int RGWRole::get(const DoutPrefixProvider *dpp, optional_yield y) |
7c673cae | 148 | { |
b3b6e05e | 149 | int ret = read_name(dpp, y); |
7c673cae FG |
150 | if (ret < 0) { |
151 | return ret; | |
152 | } | |
153 | ||
b3b6e05e | 154 | ret = read_info(dpp, y); |
7c673cae FG |
155 | if (ret < 0) { |
156 | return ret; | |
157 | } | |
158 | ||
159 | return 0; | |
160 | } | |
161 | ||
b3b6e05e | 162 | int RGWRole::get_by_id(const DoutPrefixProvider *dpp, optional_yield y) |
31f18b77 | 163 | { |
b3b6e05e | 164 | int ret = read_info(dpp, y); |
31f18b77 FG |
165 | if (ret < 0) { |
166 | return ret; | |
167 | } | |
168 | ||
169 | return 0; | |
170 | } | |
171 | ||
39ae355f TL |
172 | void RGWRole::dump(Formatter *f) const |
173 | { | |
174 | info.dump(f); | |
175 | } | |
176 | ||
177 | void RGWRole::decode_json(JSONObj *obj) | |
178 | { | |
179 | info.decode_json(obj); | |
180 | } | |
181 | ||
182 | bool RGWRole::validate_input(const DoutPrefixProvider* dpp) | |
183 | { | |
184 | if (info.name.length() > MAX_ROLE_NAME_LEN) { | |
185 | ldpp_dout(dpp, 0) << "ERROR: Invalid name length " << dendl; | |
186 | return false; | |
187 | } | |
188 | ||
189 | if (info.path.length() > MAX_PATH_NAME_LEN) { | |
190 | ldpp_dout(dpp, 0) << "ERROR: Invalid path length " << dendl; | |
191 | return false; | |
192 | } | |
193 | ||
194 | std::regex regex_name("[A-Za-z0-9:=,.@-]+"); | |
195 | if (! std::regex_match(info.name, regex_name)) { | |
196 | ldpp_dout(dpp, 0) << "ERROR: Invalid chars in name " << dendl; | |
197 | return false; | |
198 | } | |
199 | ||
200 | std::regex regex_path("(/[!-~]+/)|(/)"); | |
201 | if (! std::regex_match(info.path,regex_path)) { | |
202 | ldpp_dout(dpp, 0) << "ERROR: Invalid chars in path " << dendl; | |
203 | return false; | |
204 | } | |
205 | ||
206 | if (info.max_session_duration < SESSION_DURATION_MIN || | |
207 | info.max_session_duration > SESSION_DURATION_MAX) { | |
208 | ldpp_dout(dpp, 0) << "ERROR: Invalid session duration, should be between 3600 and 43200 seconds " << dendl; | |
209 | return false; | |
210 | } | |
211 | return true; | |
212 | } | |
213 | ||
214 | void RGWRole::extract_name_tenant(const std::string& str) { | |
215 | if (auto pos = str.find('$'); | |
216 | pos != std::string::npos) { | |
217 | info.tenant = str.substr(0, pos); | |
218 | info.name = str.substr(pos+1); | |
219 | } | |
220 | } | |
221 | ||
b3b6e05e | 222 | int RGWRole::update(const DoutPrefixProvider *dpp, optional_yield y) |
7c673cae | 223 | { |
b3b6e05e | 224 | int ret = store_info(dpp, false, y); |
7c673cae | 225 | if (ret < 0) { |
20effc67 | 226 | ldpp_dout(dpp, 0) << "ERROR: storing info in Role pool: " |
39ae355f | 227 | << info.id << ": " << cpp_strerror(-ret) << dendl; |
7c673cae FG |
228 | return ret; |
229 | } | |
230 | ||
231 | return 0; | |
232 | } | |
233 | ||
234 | void RGWRole::set_perm_policy(const string& policy_name, const string& perm_policy) | |
235 | { | |
39ae355f | 236 | info.perm_policy_map[policy_name] = perm_policy; |
7c673cae FG |
237 | } |
238 | ||
239 | vector<string> RGWRole::get_role_policy_names() | |
240 | { | |
241 | vector<string> policy_names; | |
39ae355f | 242 | for (const auto& it : info.perm_policy_map) |
7c673cae FG |
243 | { |
244 | policy_names.push_back(std::move(it.first)); | |
245 | } | |
246 | ||
247 | return policy_names; | |
248 | } | |
249 | ||
20effc67 | 250 | int RGWRole::get_role_policy(const DoutPrefixProvider* dpp, const string& policy_name, string& perm_policy) |
7c673cae | 251 | { |
39ae355f TL |
252 | const auto it = info.perm_policy_map.find(policy_name); |
253 | if (it == info.perm_policy_map.end()) { | |
20effc67 | 254 | ldpp_dout(dpp, 0) << "ERROR: Policy name: " << policy_name << " not found" << dendl; |
92f5a8d4 | 255 | return -ENOENT; |
7c673cae FG |
256 | } else { |
257 | perm_policy = it->second; | |
258 | } | |
259 | return 0; | |
260 | } | |
261 | ||
20effc67 | 262 | int RGWRole::delete_policy(const DoutPrefixProvider* dpp, const string& policy_name) |
7c673cae | 263 | { |
39ae355f TL |
264 | const auto& it = info.perm_policy_map.find(policy_name); |
265 | if (it == info.perm_policy_map.end()) { | |
20effc67 | 266 | ldpp_dout(dpp, 0) << "ERROR: Policy name: " << policy_name << " not found" << dendl; |
7c673cae FG |
267 | return -ENOENT; |
268 | } else { | |
39ae355f | 269 | info.perm_policy_map.erase(it); |
7c673cae FG |
270 | } |
271 | return 0; | |
272 | } | |
273 | ||
7c673cae FG |
274 | void RGWRole::update_trust_policy(string& trust_policy) |
275 | { | |
39ae355f | 276 | this->info.trust_policy = trust_policy; |
7c673cae FG |
277 | } |
278 | ||
20effc67 | 279 | int RGWRole::set_tags(const DoutPrefixProvider* dpp, const multimap<string,string>& tags_map) |
7c673cae | 280 | { |
20effc67 | 281 | for (auto& it : tags_map) { |
39ae355f | 282 | this->info.tags.emplace(it.first, it.second); |
7c673cae | 283 | } |
39ae355f | 284 | if (this->info.tags.size() > 50) { |
20effc67 TL |
285 | ldpp_dout(dpp, 0) << "No. of tags is greater than 50" << dendl; |
286 | return -EINVAL; | |
287 | } | |
288 | return 0; | |
289 | } | |
7c673cae | 290 | |
20effc67 TL |
291 | boost::optional<multimap<string,string>> RGWRole::get_tags() |
292 | { | |
39ae355f | 293 | if(this->info.tags.empty()) { |
20effc67 | 294 | return boost::none; |
7c673cae | 295 | } |
39ae355f | 296 | return this->info.tags; |
20effc67 | 297 | } |
7c673cae | 298 | |
20effc67 TL |
299 | void RGWRole::erase_tags(const vector<string>& tagKeys) |
300 | { | |
301 | for (auto& it : tagKeys) { | |
39ae355f | 302 | this->info.tags.erase(it); |
20effc67 | 303 | } |
7c673cae FG |
304 | } |
305 | ||
306 | const string& RGWRole::get_names_oid_prefix() | |
307 | { | |
308 | return role_name_oid_prefix; | |
309 | } | |
310 | ||
311 | const string& RGWRole::get_info_oid_prefix() | |
312 | { | |
313 | return role_oid_prefix; | |
314 | } | |
315 | ||
316 | const string& RGWRole::get_path_oid_prefix() | |
317 | { | |
318 | return role_path_oid_prefix; | |
319 | } | |
20effc67 | 320 | |
39ae355f TL |
321 | RGWRoleMetadataHandler::RGWRoleMetadataHandler(Store* store, |
322 | RGWSI_Role_RADOS *role_svc) | |
323 | { | |
324 | this->store = store; | |
325 | base_init(role_svc->ctx(), role_svc->get_be_handler()); | |
326 | } | |
327 | ||
328 | RGWMetadataObject *RGWRoleMetadataHandler::get_meta_obj(JSONObj *jo, | |
329 | const obj_version& objv, | |
330 | const ceph::real_time& mtime) | |
331 | { | |
332 | RGWRoleInfo info; | |
333 | ||
334 | try { | |
335 | info.decode_json(jo); | |
336 | } catch (JSONDecoder:: err& e) { | |
337 | return nullptr; | |
338 | } | |
339 | ||
340 | return new RGWRoleMetadataObject(info, objv, mtime, store); | |
341 | } | |
342 | ||
343 | int RGWRoleMetadataHandler::do_get(RGWSI_MetaBackend_Handler::Op *op, | |
344 | std::string& entry, | |
345 | RGWMetadataObject **obj, | |
346 | optional_yield y, | |
347 | const DoutPrefixProvider *dpp) | |
348 | { | |
349 | std::unique_ptr<rgw::sal::RGWRole> role = store->get_role(entry); | |
350 | int ret = role->read_info(dpp, y); | |
351 | if (ret < 0) { | |
352 | return ret; | |
353 | } | |
354 | ||
355 | RGWObjVersionTracker objv_tracker = role->get_objv_tracker(); | |
356 | real_time mtime = role->get_mtime(); | |
357 | ||
358 | RGWRoleInfo info = role->get_info(); | |
359 | RGWRoleMetadataObject *rdo = new RGWRoleMetadataObject(info, objv_tracker.read_version, | |
360 | mtime, store); | |
361 | *obj = rdo; | |
362 | ||
363 | return 0; | |
364 | } | |
365 | ||
366 | int RGWRoleMetadataHandler::do_remove(RGWSI_MetaBackend_Handler::Op *op, | |
367 | std::string& entry, | |
368 | RGWObjVersionTracker& objv_tracker, | |
369 | optional_yield y, | |
370 | const DoutPrefixProvider *dpp) | |
371 | { | |
372 | std::unique_ptr<rgw::sal::RGWRole> role = store->get_role(entry); | |
373 | int ret = role->read_info(dpp, y); | |
374 | if (ret < 0) { | |
375 | return ret == -ENOENT? 0 : ret; | |
376 | } | |
377 | ||
378 | return role->delete_obj(dpp, y); | |
379 | } | |
380 | ||
381 | class RGWMetadataHandlerPut_Role : public RGWMetadataHandlerPut_SObj | |
382 | { | |
383 | RGWRoleMetadataHandler *rhandler; | |
384 | RGWRoleMetadataObject *mdo; | |
385 | public: | |
386 | RGWMetadataHandlerPut_Role(RGWRoleMetadataHandler *handler, | |
387 | RGWSI_MetaBackend_Handler::Op *op, | |
388 | std::string& entry, | |
389 | RGWMetadataObject *obj, | |
390 | RGWObjVersionTracker& objv_tracker, | |
391 | optional_yield y, | |
392 | RGWMDLogSyncType type, | |
393 | bool from_remote_zone) : | |
394 | RGWMetadataHandlerPut_SObj(handler, op, entry, obj, objv_tracker, y, type, from_remote_zone), | |
395 | rhandler(handler) { | |
396 | mdo = static_cast<RGWRoleMetadataObject*>(obj); | |
397 | } | |
398 | ||
399 | int put_checked(const DoutPrefixProvider *dpp) override { | |
400 | auto& info = mdo->get_role_info(); | |
401 | auto mtime = mdo->get_mtime(); | |
402 | auto* store = mdo->get_store(); | |
403 | info.mtime = mtime; | |
404 | std::unique_ptr<rgw::sal::RGWRole> role = store->get_role(info); | |
405 | int ret = role->create(dpp, true, info.id, y); | |
406 | if (ret == -EEXIST) { | |
407 | ret = role->update(dpp, y); | |
408 | } | |
409 | ||
410 | return ret < 0 ? ret : STATUS_APPLIED; | |
411 | } | |
412 | }; | |
413 | ||
414 | int RGWRoleMetadataHandler::do_put(RGWSI_MetaBackend_Handler::Op *op, | |
415 | std::string& entry, | |
416 | RGWMetadataObject *obj, | |
417 | RGWObjVersionTracker& objv_tracker, | |
418 | optional_yield y, | |
419 | const DoutPrefixProvider *dpp, | |
420 | RGWMDLogSyncType type, | |
421 | bool from_remote_zone) | |
422 | { | |
423 | RGWMetadataHandlerPut_Role put_op(this, op , entry, obj, objv_tracker, y, type, from_remote_zone); | |
424 | return do_put_operate(&put_op, dpp); | |
425 | } | |
426 | ||
20effc67 | 427 | } } // namespace rgw::sal |