diff options
Diffstat (limited to 'src/rgw/rgw_role.cc')
-rw-r--r-- | src/rgw/rgw_role.cc | 444 |
1 files changed, 444 insertions, 0 deletions
diff --git a/src/rgw/rgw_role.cc b/src/rgw/rgw_role.cc new file mode 100644 index 000000000..fb188e7f8 --- /dev/null +++ b/src/rgw/rgw_role.cc @@ -0,0 +1,444 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab ft=cpp + +#include <errno.h> +#include <ctime> +#include <regex> +#include <boost/algorithm/string/replace.hpp> + +#include "common/errno.h" +#include "common/Formatter.h" +#include "common/ceph_json.h" +#include "common/ceph_time.h" +#include "rgw_rados.h" +#include "rgw_zone.h" + +#include "include/types.h" +#include "rgw_string.h" + +#include "rgw_common.h" +#include "rgw_tools.h" +#include "rgw_role.h" + +#include "services/svc_zone.h" +#include "services/svc_sys_obj.h" +#include "services/svc_meta_be_sobj.h" +#include "services/svc_meta.h" +#include "services/svc_role_rados.h" + +#define dout_subsys ceph_subsys_rgw + +using namespace std; + +namespace rgw { namespace sal { + +const string RGWRole::role_name_oid_prefix = "role_names."; +const string RGWRole::role_oid_prefix = "roles."; +const string RGWRole::role_path_oid_prefix = "role_paths."; +const string RGWRole::role_arn_prefix = "arn:aws:iam::"; + +void RGWRoleInfo::dump(Formatter *f) const +{ + encode_json("RoleId", id , f); + std::string role_name; + if (tenant.empty()) { + role_name = name; + } else { + role_name = tenant + '$' + name; + } + encode_json("RoleName", role_name , f); + encode_json("Path", path, f); + encode_json("Arn", arn, f); + encode_json("CreateDate", creation_date, f); + encode_json("MaxSessionDuration", max_session_duration, f); + encode_json("AssumeRolePolicyDocument", trust_policy, f); + if (!perm_policy_map.empty()) { + f->open_array_section("PermissionPolicies"); + for (const auto& it : perm_policy_map) { + f->open_object_section("Policy"); + encode_json("PolicyName", it.first, f); + encode_json("PolicyValue", it.second, f); + f->close_section(); + } + f->close_section(); + } + if (!tags.empty()) { + f->open_array_section("Tags"); + for (const auto& it : tags) { + f->open_object_section("Tag"); + encode_json("Key", it.first, f); + encode_json("Value", it.second, f); + f->close_section(); + } + f->close_section(); + } +} + +void RGWRoleInfo::decode_json(JSONObj *obj) +{ + JSONDecoder::decode_json("RoleId", id, obj); + JSONDecoder::decode_json("RoleName", name, obj); + JSONDecoder::decode_json("Path", path, obj); + JSONDecoder::decode_json("Arn", arn, obj); + JSONDecoder::decode_json("CreateDate", creation_date, obj); + JSONDecoder::decode_json("MaxSessionDuration", max_session_duration, obj); + JSONDecoder::decode_json("AssumeRolePolicyDocument", trust_policy, obj); + + auto tags_iter = obj->find_first("Tags"); + if (!tags_iter.end()) { + JSONObj* tags_json = *tags_iter; + auto iter = tags_json->find_first(); + + for (; !iter.end(); ++iter) { + std::string key, val; + JSONDecoder::decode_json("Key", key, *iter); + JSONDecoder::decode_json("Value", val, *iter); + this->tags.emplace(key, val); + } + } + + auto perm_policy_iter = obj->find_first("PermissionPolicies"); + if (!perm_policy_iter.end()) { + JSONObj* perm_policies = *perm_policy_iter; + auto iter = perm_policies->find_first(); + + for (; !iter.end(); ++iter) { + std::string policy_name, policy_val; + JSONDecoder::decode_json("PolicyName", policy_name, *iter); + JSONDecoder::decode_json("PolicyValue", policy_val, *iter); + this->perm_policy_map.emplace(policy_name, policy_val); + } + } + + if (auto pos = name.find('$'); pos != std::string::npos) { + tenant = name.substr(0, pos); + name = name.substr(pos+1); + } +} + +RGWRole::RGWRole(std::string name, + std::string tenant, + std::string path, + std::string trust_policy, + std::string max_session_duration_str, + std::multimap<std::string,std::string> tags) +{ + info.name = std::move(name); + info.path = std::move(path); + info.trust_policy = std::move(trust_policy); + info.tenant = std::move(tenant); + info.tags = std::move(tags); + if (this->info.path.empty()) + this->info.path = "/"; + extract_name_tenant(this->info.name); + if (max_session_duration_str.empty()) { + info.max_session_duration = SESSION_DURATION_MIN; + } else { + info.max_session_duration = std::stoull(max_session_duration_str); + } + info.mtime = real_time(); +} + +RGWRole::RGWRole(std::string id) +{ + info.id = std::move(id); +} + +int RGWRole::get(const DoutPrefixProvider *dpp, optional_yield y) +{ + int ret = read_name(dpp, y); + if (ret < 0) { + return ret; + } + + ret = read_info(dpp, y); + if (ret < 0) { + return ret; + } + + return 0; +} + +int RGWRole::get_by_id(const DoutPrefixProvider *dpp, optional_yield y) +{ + int ret = read_info(dpp, y); + if (ret < 0) { + return ret; + } + + return 0; +} + +void RGWRole::dump(Formatter *f) const +{ + info.dump(f); +} + +void RGWRole::decode_json(JSONObj *obj) +{ + info.decode_json(obj); +} + +bool RGWRole::validate_max_session_duration(const DoutPrefixProvider* dpp) +{ + if (info.max_session_duration < SESSION_DURATION_MIN || + info.max_session_duration > SESSION_DURATION_MAX) { + ldpp_dout(dpp, 0) << "ERROR: Invalid session duration, should be between 3600 and 43200 seconds " << dendl; + return false; + } + return true; +} + +bool RGWRole::validate_input(const DoutPrefixProvider* dpp) +{ + if (info.name.length() > MAX_ROLE_NAME_LEN) { + ldpp_dout(dpp, 0) << "ERROR: Invalid name length " << dendl; + return false; + } + + if (info.path.length() > MAX_PATH_NAME_LEN) { + ldpp_dout(dpp, 0) << "ERROR: Invalid path length " << dendl; + return false; + } + + std::regex regex_name("[A-Za-z0-9:=,.@-]+"); + if (! std::regex_match(info.name, regex_name)) { + ldpp_dout(dpp, 0) << "ERROR: Invalid chars in name " << dendl; + return false; + } + + std::regex regex_path("(/[!-~]+/)|(/)"); + if (! std::regex_match(info.path,regex_path)) { + ldpp_dout(dpp, 0) << "ERROR: Invalid chars in path " << dendl; + return false; + } + + if (!validate_max_session_duration(dpp)) { + return false; + } + return true; +} + +void RGWRole::extract_name_tenant(const std::string& str) { + if (auto pos = str.find('$'); + pos != std::string::npos) { + info.tenant = str.substr(0, pos); + info.name = str.substr(pos+1); + } +} + +int RGWRole::update(const DoutPrefixProvider *dpp, optional_yield y) +{ + int ret = store_info(dpp, false, y); + if (ret < 0) { + ldpp_dout(dpp, 0) << "ERROR: storing info in Role pool: " + << info.id << ": " << cpp_strerror(-ret) << dendl; + return ret; + } + + return 0; +} + +void RGWRole::set_perm_policy(const string& policy_name, const string& perm_policy) +{ + info.perm_policy_map[policy_name] = perm_policy; +} + +vector<string> RGWRole::get_role_policy_names() +{ + vector<string> policy_names; + for (const auto& it : info.perm_policy_map) + { + policy_names.push_back(std::move(it.first)); + } + + return policy_names; +} + +int RGWRole::get_role_policy(const DoutPrefixProvider* dpp, const string& policy_name, string& perm_policy) +{ + const auto it = info.perm_policy_map.find(policy_name); + if (it == info.perm_policy_map.end()) { + ldpp_dout(dpp, 0) << "ERROR: Policy name: " << policy_name << " not found" << dendl; + return -ENOENT; + } else { + perm_policy = it->second; + } + return 0; +} + +int RGWRole::delete_policy(const DoutPrefixProvider* dpp, const string& policy_name) +{ + const auto& it = info.perm_policy_map.find(policy_name); + if (it == info.perm_policy_map.end()) { + ldpp_dout(dpp, 0) << "ERROR: Policy name: " << policy_name << " not found" << dendl; + return -ENOENT; + } else { + info.perm_policy_map.erase(it); + } + return 0; +} + +void RGWRole::update_trust_policy(string& trust_policy) +{ + this->info.trust_policy = trust_policy; +} + +int RGWRole::set_tags(const DoutPrefixProvider* dpp, const multimap<string,string>& tags_map) +{ + for (auto& it : tags_map) { + this->info.tags.emplace(it.first, it.second); + } + if (this->info.tags.size() > 50) { + ldpp_dout(dpp, 0) << "No. of tags is greater than 50" << dendl; + return -EINVAL; + } + return 0; +} + +boost::optional<multimap<string,string>> RGWRole::get_tags() +{ + if(this->info.tags.empty()) { + return boost::none; + } + return this->info.tags; +} + +void RGWRole::erase_tags(const vector<string>& tagKeys) +{ + for (auto& it : tagKeys) { + this->info.tags.erase(it); + } +} + +void RGWRole::update_max_session_duration(const std::string& max_session_duration_str) +{ + if (max_session_duration_str.empty()) { + info.max_session_duration = SESSION_DURATION_MIN; + } else { + info.max_session_duration = std::stoull(max_session_duration_str); + } +} + +const string& RGWRole::get_names_oid_prefix() +{ + return role_name_oid_prefix; +} + +const string& RGWRole::get_info_oid_prefix() +{ + return role_oid_prefix; +} + +const string& RGWRole::get_path_oid_prefix() +{ + return role_path_oid_prefix; +} + +RGWRoleMetadataHandler::RGWRoleMetadataHandler(Driver* driver, + RGWSI_Role_RADOS *role_svc) +{ + this->driver = driver; + base_init(role_svc->ctx(), role_svc->get_be_handler()); +} + +RGWMetadataObject *RGWRoleMetadataHandler::get_meta_obj(JSONObj *jo, + const obj_version& objv, + const ceph::real_time& mtime) +{ + RGWRoleInfo info; + + try { + info.decode_json(jo); + } catch (JSONDecoder:: err& e) { + return nullptr; + } + + return new RGWRoleMetadataObject(info, objv, mtime, driver); +} + +int RGWRoleMetadataHandler::do_get(RGWSI_MetaBackend_Handler::Op *op, + std::string& entry, + RGWMetadataObject **obj, + optional_yield y, + const DoutPrefixProvider *dpp) +{ + std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(entry); + int ret = role->read_info(dpp, y); + if (ret < 0) { + return ret; + } + + RGWObjVersionTracker objv_tracker = role->get_objv_tracker(); + real_time mtime = role->get_mtime(); + + RGWRoleInfo info = role->get_info(); + RGWRoleMetadataObject *rdo = new RGWRoleMetadataObject(info, objv_tracker.read_version, + mtime, driver); + *obj = rdo; + + return 0; +} + +int RGWRoleMetadataHandler::do_remove(RGWSI_MetaBackend_Handler::Op *op, + std::string& entry, + RGWObjVersionTracker& objv_tracker, + optional_yield y, + const DoutPrefixProvider *dpp) +{ + std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(entry); + int ret = role->read_info(dpp, y); + if (ret < 0) { + return ret == -ENOENT? 0 : ret; + } + + return role->delete_obj(dpp, y); +} + +class RGWMetadataHandlerPut_Role : public RGWMetadataHandlerPut_SObj +{ + RGWRoleMetadataHandler *rhandler; + RGWRoleMetadataObject *mdo; +public: + RGWMetadataHandlerPut_Role(RGWRoleMetadataHandler *handler, + RGWSI_MetaBackend_Handler::Op *op, + std::string& entry, + RGWMetadataObject *obj, + RGWObjVersionTracker& objv_tracker, + optional_yield y, + RGWMDLogSyncType type, + bool from_remote_zone) : + RGWMetadataHandlerPut_SObj(handler, op, entry, obj, objv_tracker, y, type, from_remote_zone), + rhandler(handler) { + mdo = static_cast<RGWRoleMetadataObject*>(obj); + } + + int put_checked(const DoutPrefixProvider *dpp) override { + auto& info = mdo->get_role_info(); + auto mtime = mdo->get_mtime(); + auto* driver = mdo->get_driver(); + info.mtime = mtime; + std::unique_ptr<rgw::sal::RGWRole> role = driver->get_role(info); + int ret = role->create(dpp, true, info.id, y); + if (ret == -EEXIST) { + ret = role->update(dpp, y); + } + + return ret < 0 ? ret : STATUS_APPLIED; + } +}; + +int RGWRoleMetadataHandler::do_put(RGWSI_MetaBackend_Handler::Op *op, + std::string& entry, + RGWMetadataObject *obj, + RGWObjVersionTracker& objv_tracker, + optional_yield y, + const DoutPrefixProvider *dpp, + RGWMDLogSyncType type, + bool from_remote_zone) +{ + RGWMetadataHandlerPut_Role put_op(this, op , entry, obj, objv_tracker, y, type, from_remote_zone); + return do_put_operate(&put_op, dpp); +} + +} } // namespace rgw::sal |