From bb2ba14dfc4113030f4a8dc17b15f23a39b40b09 Mon Sep 17 00:00:00 2001 From: Casey Bodley Date: Mon, 4 Dec 2023 16:47:12 -0500 Subject: [PATCH] rgw/role: add rgwrados::role interface for role metadata move everything from class RadosRole into driver/rados/role.cc and use RGWSI_SysObj instead of the metadata backend. narrows the RGWRole interface by handling the name/path objects internally rgwrados::role::write() adds/remove name and path linkages in case they change. admin ops don't allow this, but 'metadata put' could upload arbitrary json that does change them Signed-off-by: Casey Bodley --- src/rgw/CMakeLists.txt | 1 + src/rgw/driver/rados/rgw_sal_rados.cc | 401 ++------------ src/rgw/driver/rados/rgw_sal_rados.h | 13 +- src/rgw/driver/rados/rgw_service.cc | 5 +- src/rgw/driver/rados/role.cc | 720 ++++++++++++++++++++++++++ src/rgw/driver/rados/role.h | 81 +++ src/rgw/rgw_admin.cc | 40 +- src/rgw/rgw_rest_iam.h | 2 +- src/rgw/rgw_rest_role.cc | 43 +- src/rgw/rgw_rest_role.h | 1 - src/rgw/rgw_rest_s3.cc | 2 +- src/rgw/rgw_rest_sts.cc | 2 +- src/rgw/rgw_role.cc | 271 ++-------- src/rgw/rgw_role.h | 35 +- src/rgw/rgw_sts.cc | 2 +- 15 files changed, 940 insertions(+), 679 deletions(-) create mode 100644 src/rgw/driver/rados/role.cc create mode 100644 src/rgw/driver/rados/role.h diff --git a/src/rgw/CMakeLists.txt b/src/rgw/CMakeLists.txt index 792569ff482a6..c09491200c6b1 100644 --- a/src/rgw/CMakeLists.txt +++ b/src/rgw/CMakeLists.txt @@ -202,6 +202,7 @@ set(librgw_common_srcs driver/rados/rgw_trim_mdlog.cc driver/rados/rgw_user.cc driver/rados/rgw_zone.cc + driver/rados/role.cc driver/rados/roles.cc driver/rados/sync_fairness.cc driver/rados/topic.cc diff --git a/src/rgw/driver/rados/rgw_sal_rados.cc b/src/rgw/driver/rados/rgw_sal_rados.cc index e3b435d283919..92b8582e92f2a 100644 --- a/src/rgw/driver/rados/rgw_sal_rados.cc +++ b/src/rgw/driver/rados/rgw_sal_rados.cc @@ -28,6 +28,7 @@ #include "common/Clock.h" #include "common/errno.h" +#include "role.h" #include "rgw_sal.h" #include "rgw_sal_rados.h" #include "rgw_bucket.h" @@ -1286,15 +1287,16 @@ int RadosStore::list_account_roles(const DoutPrefixProvider* dpp, // load the role metadata for each for (const auto& id : ids) { - std::unique_ptr role = get_role(id); - r = role->read_info(dpp, y); + RGWRoleInfo info; + r = rgwrados::role::read_by_id(dpp, y, *svc()->sysobj, zone, id, + info, nullptr, nullptr, nullptr); if (r == -ENOENT) { continue; } if (r < 0) { return r; } - listing.roles.push_back(std::move(role->get_info())); + listing.roles.push_back(std::move(info)); } return 0; @@ -2016,67 +2018,10 @@ int RadosStore::list_roles(const DoutPrefixProvider *dpp, uint32_t max_items, RoleList& listing) { - listing.roles.clear(); - - const auto& pool = svc()->zone->get_zone_params().roles_pool; - std::string prefix; - - // List all roles if path prefix is empty - if (! path_prefix.empty()) { - prefix = tenant + RGWRole::role_path_oid_prefix + path_prefix; - } else { - prefix = tenant + RGWRole::role_path_oid_prefix; - } - - //Get the filtered objects - RGWListRawObjsCtx ctx; - int r = rados->list_raw_objects_init(dpp, pool, marker, &ctx); - if (r < 0) { - return r; - } - - bool is_truncated = false; - list oids; - r = rados->list_raw_objects(dpp, pool, prefix, max_items, - ctx, oids, &is_truncated); - if (r == -ENOENT) { - r = 0; - } else if (r < 0) { - return r; - } - - for (const auto& oid : oids) { - const std::string key = oid.substr(RGWRole::role_path_oid_prefix.size()); - - //Find the role oid prefix from the end - size_t pos = key.rfind(RGWRole::role_oid_prefix); - if (pos == std::string::npos) { - continue; - } - // Split the result into path and info_oid + id - std::string path = key.substr(0, pos); - - /*Make sure that prefix is part of path (False results could've been returned) - because of the role info oid + id appended to the path)*/ - if(path_prefix.empty() || path.find(path_prefix) != std::string::npos) { - //Get id from info oid prefix + id - std::string id = key.substr(pos + RGWRole::role_oid_prefix.length()); - - std::unique_ptr role = get_role(id); - r = role->read_info(dpp, y); - if (r < 0) { - return r; - } - listing.roles.push_back(std::move(role->get_info())); - } - } - - if (is_truncated) { - listing.next_marker = rados->list_raw_objs_get_cursor(ctx); - } else { - listing.next_marker.clear(); - } - return 0; + const RGWZoneParams& zone = svc()->zone->get_zone_params(); + return rgwrados::role::list_tenant(dpp, y, *svc()->sysobj, zone, + tenant, marker, max_items, path_prefix, + listing.roles, listing.next_marker); } static constexpr std::string_view oidc_url_oid_prefix = "oidc_url."; @@ -4434,321 +4379,39 @@ std::ostream& RadosLuaManager::PackagesWatcher::gen_prefix(std::ostream& out) co int RadosRole::store_info(const DoutPrefixProvider *dpp, bool exclusive, optional_yield y) { - using ceph::encode; - std::string oid; - - oid = info.id; - - bufferlist bl; - encode(this->info, bl); - - if (!this->info.tags.empty()) { - bufferlist bl_tags; - encode(this->info.tags, bl_tags); - map attrs; - attrs.emplace("tagging", bl_tags); - - RGWSI_MBSObj_PutParams params(bl, &attrs, info.mtime, exclusive); - std::unique_ptr ctx(store->svc()->role->svc.meta_be->alloc_ctx()); - ctx->init(store->svc()->role->get_be_handler()); - return store->svc()->role->svc.meta_be->put(ctx.get(), oid, params, &info.objv_tracker, y, dpp); - } else { - RGWSI_MBSObj_PutParams params(bl, nullptr, info.mtime, exclusive); - std::unique_ptr ctx(store->svc()->role->svc.meta_be->alloc_ctx()); - ctx->init(store->svc()->role->get_be_handler()); - return store->svc()->role->svc.meta_be->put(ctx.get(), oid, params, &info.objv_tracker, y, dpp); - } -} - -static std::string role_name_oid(const RGWRoleInfo& r, std::string_view prefix) -{ - if (!r.account_id.empty()) { - // names are case-insensitive, so store them in lower case - std::string lower_name = r.name; - boost::algorithm::to_lower(lower_name); - // use account id as prefix - return string_cat_reserve(r.account_id, prefix, lower_name); - } else { - // use tenant as prefix - return string_cat_reserve(r.tenant, prefix, r.name); - } -} - -int RadosRole::store_name(const DoutPrefixProvider *dpp, bool exclusive, optional_yield y) -{ - auto sysobj = store->svc()->sysobj; - RGWNameToId nameToId; - nameToId.obj_id = info.id; - - std::string oid = role_name_oid(info, get_names_oid_prefix()); - - bufferlist bl; - using ceph::encode; - encode(nameToId, bl); - - return rgw_put_system_obj(dpp, sysobj, store->svc()->zone->get_zone_params().roles_pool, oid, bl, exclusive, &info.objv_tracker, real_time(), y); -} - -int RadosRole::store_path(const DoutPrefixProvider *dpp, bool exclusive, optional_yield y) -{ - if (!info.account_id.empty()) { - librados::Rados& rados = *store->getRados()->get_rados_handle(); - const RGWZoneParams& zone = store->svc()->zone->get_zone_params(); - const rgw_raw_obj& obj = rgwrados::account::get_roles_obj(zone, info.account_id); - constexpr uint32_t no_limit = std::numeric_limits::max(); - return rgwrados::roles::add(dpp, y, rados, obj, info, false, no_limit); - } - - auto sysobj = store->svc()->sysobj; - std::string oid = info.tenant + get_path_oid_prefix() + info.path + get_info_oid_prefix() + info.id; - - bufferlist bl; - - return rgw_put_system_obj(dpp, sysobj, store->svc()->zone->get_zone_params().roles_pool, oid, bl, exclusive, &info.objv_tracker, real_time(), y); -} - -int RadosRole::read_id(const DoutPrefixProvider *dpp, const std::string& role_name, const std::string& tenant, std::string& role_id, optional_yield y) -{ - auto sysobj = store->svc()->sysobj; - std::string oid = info.tenant + get_names_oid_prefix() + role_name; - bufferlist bl; - - int ret = rgw_get_system_obj(sysobj, store->svc()->zone->get_zone_params().roles_pool, oid, bl, nullptr, nullptr, y, dpp); - if (ret < 0) { - return ret; - } - - RGWNameToId nameToId; - try { - auto iter = bl.cbegin(); - using ceph::decode; - decode(nameToId, iter); - } catch (buffer::error& err) { - ldpp_dout(dpp, 0) << "ERROR: failed to decode role from Role pool: " << role_name << dendl; - return -EIO; - } - role_id = nameToId.obj_id; - return 0; -} - -int RadosRole::read_name(const DoutPrefixProvider *dpp, optional_yield y) -{ - auto sysobj = store->svc()->sysobj; - std::string oid = role_name_oid(info, get_names_oid_prefix()); - bufferlist bl; - - int ret = rgw_get_system_obj(sysobj, store->svc()->zone->get_zone_params().roles_pool, oid, bl, nullptr, nullptr, y, dpp); - if (ret < 0) { - ldpp_dout(dpp, 0) << "ERROR: failed reading role name from Role pool: " << info.name << - ": " << cpp_strerror(-ret) << dendl; - return ret; - } - - RGWNameToId nameToId; - try { - using ceph::decode; - auto iter = bl.cbegin(); - decode(nameToId, iter); - } catch (buffer::error& err) { - ldpp_dout(dpp, 0) << "ERROR: failed to decode role name from Role pool: " << info.name << dendl; - return -EIO; - } - info.id = nameToId.obj_id; - return 0; + librados::Rados& rados = *store->getRados()->get_rados_handle(); + RGWServices* svc = store->svc(); + const RGWZoneParams& zone = svc->zone->get_zone_params(); + return rgwrados::role::write(dpp, y, rados, *svc->sysobj, svc->mdlog, + zone, info, info.objv_tracker, + ceph::real_time{}, exclusive); } -int RadosRole::read_info(const DoutPrefixProvider *dpp, optional_yield y) +int RadosRole::load_by_name(const DoutPrefixProvider *dpp, optional_yield y) { - std::string oid; - - oid = info.id; - ldpp_dout(dpp, 20) << "INFO: oid in read_info is: " << oid << dendl; - - bufferlist bl; - - RGWSI_MBSObj_GetParams params(&bl, &info.attrs, &info.mtime); - std::unique_ptr ctx(store->svc()->role->svc.meta_be->alloc_ctx()); - ctx->init(store->svc()->role->get_be_handler()); - int ret = store->svc()->role->svc.meta_be->get(ctx.get(), oid, params, &info.objv_tracker, y, dpp, true); - if (ret < 0) { - ldpp_dout(dpp, 0) << "ERROR: failed reading role info from Role pool: " << info.id << ": " << cpp_strerror(-ret) << dendl; - return ret; - } - - try { - using ceph::decode; - auto iter = bl.cbegin(); - decode(this->info, iter); - } catch (buffer::error& err) { - ldpp_dout(dpp, 0) << "ERROR: failed to decode role info from Role pool: " << info.id << dendl; - return -EIO; - } - - auto it = info.attrs.find("tagging"); - if (it != info.attrs.end()) { - bufferlist bl_tags = it->second; - try { - using ceph::decode; - auto iter = bl_tags.cbegin(); - decode(info.tags, iter); - } catch (buffer::error& err) { - ldpp_dout(dpp, 0) << "ERROR: failed to decode attrs" << info.id << dendl; - return -EIO; - } - } - - return 0; + RGWServices* svc = store->svc(); + const RGWZoneParams& zone = svc->zone->get_zone_params(); + return rgwrados::role::read_by_name(dpp, y, *svc->sysobj, zone, + info.tenant, info.account_id, + info.name, info, &info.mtime, + &info.objv_tracker); } -int RadosRole::create(const DoutPrefixProvider *dpp, bool exclusive, const std::string& role_id, optional_yield y) +int RadosRole::load_by_id(const DoutPrefixProvider *dpp, optional_yield y) { - int ret; - - if (! validate_input(dpp)) { - return -EINVAL; - } - - if (!role_id.empty()) { - info.id = role_id; - } - - /* check to see the name is not used */ - ret = read_id(dpp, info.name, info.tenant, info.id, y); - if (exclusive && ret == 0) { - ldpp_dout(dpp, 0) << "ERROR: name " << info.name << " already in use for role id " - << info.id << dendl; - return -EEXIST; - } else if ( ret < 0 && ret != -ENOENT) { - ldpp_dout(dpp, 0) << "failed reading role id " << info.id << ": " - << cpp_strerror(-ret) << dendl; - return ret; - } - - if (info.id.empty()) { - /* create unique id */ - uuid_d new_uuid; - char uuid_str[37]; - new_uuid.generate_random(); - new_uuid.print(uuid_str); - info.id = uuid_str; - } - - //arn - std::string_view account = !info.account_id.empty() ? info.account_id : info.tenant; - info.arn = string_cat_reserve(role_arn_prefix, account, ":role", info.path, info.name); - - if (info.creation_date.empty()) { - // Creation time - real_clock::time_point t = real_clock::now(); - - struct timeval tv; - real_clock::to_timeval(t, tv); - - char buf[30]; - struct tm result; - gmtime_r(&tv.tv_sec, &result); - strftime(buf,30,"%Y-%m-%dT%H:%M:%S", &result); - sprintf(buf + strlen(buf),".%03dZ",(int)tv.tv_usec/1000); - info.creation_date.assign(buf, strlen(buf)); - } - - auto& pool = store->svc()->zone->get_zone_params().roles_pool; - ret = store_info(dpp, exclusive, y); - if (ret < 0) { - ldpp_dout(dpp, 0) << "ERROR: storing role info in Role pool: " - << info.id << ": " << cpp_strerror(-ret) << dendl; - return ret; - } - - ret = store_name(dpp, exclusive, y); - if (ret < 0) { - ldpp_dout(dpp, 0) << "ERROR: storing role name in Role pool: " - << info.name << ": " << cpp_strerror(-ret) << dendl; - - //Delete the role info that was stored in the previous call - std::string oid = get_info_oid_prefix() + info.id; - int info_ret = rgw_delete_system_obj(dpp, store->svc()->sysobj, pool, oid, nullptr, y); - if (info_ret < 0) { - ldpp_dout(dpp, 0) << "ERROR: cleanup of role id from Role pool: " - << info.id << ": " << cpp_strerror(-info_ret) << dendl; - } - return ret; - } - - ret = store_path(dpp, exclusive, y); - if (ret < 0) { - ldpp_dout(dpp, 0) << "ERROR: storing role path in Role pool: " - << info.path << ": " << cpp_strerror(-ret) << dendl; - //Delete the role info that was stored in the previous call - std::string oid = get_info_oid_prefix() + info.id; - int info_ret = rgw_delete_system_obj(dpp, store->svc()->sysobj, pool, oid, nullptr, y); - if (info_ret < 0) { - ldpp_dout(dpp, 0) << "ERROR: cleanup of role id from Role pool: " - << info.id << ": " << cpp_strerror(-info_ret) << dendl; - } - //Delete role name that was stored in previous call - oid = role_name_oid(info, get_names_oid_prefix()); - int name_ret = rgw_delete_system_obj(dpp, store->svc()->sysobj, pool, oid, nullptr, y); - if (name_ret < 0) { - ldpp_dout(dpp, 0) << "ERROR: cleanup of role name from Role pool: " - << info.name << ": " << cpp_strerror(-name_ret) << dendl; - } - return ret; - } - return 0; + RGWServices* svc = store->svc(); + const RGWZoneParams& zone = svc->zone->get_zone_params(); + return rgwrados::role::read_by_id(dpp, y, *svc->sysobj, zone, info.id, + info, &info.mtime, &info.objv_tracker); } int RadosRole::delete_obj(const DoutPrefixProvider *dpp, optional_yield y) { - auto& pool = store->svc()->zone->get_zone_params().roles_pool; - - int ret = read_name(dpp, y); - if (ret < 0) { - return ret; - } - - ret = read_info(dpp, y); - if (ret < 0) { - return ret; - } - - // Delete id & insert MD Log - RGWSI_MBSObj_RemoveParams params; - std::unique_ptr ctx(store->svc()->role->svc.meta_be->alloc_ctx()); - ctx->init(store->svc()->role->get_be_handler()); - ret = store->svc()->role->svc.meta_be->remove(ctx.get(), info.id, params, &info.objv_tracker, y, dpp); - if (ret < 0) { - ldpp_dout(dpp, 0) << "ERROR: deleting role id: " << info.id << " failed with code: " << cpp_strerror(-ret) << dendl; - return ret; - } - - // Delete name - std::string oid = role_name_oid(info, get_names_oid_prefix()); - ret = rgw_delete_system_obj(dpp, store->svc()->sysobj, pool, oid, nullptr, y); - if (ret < 0) { - ldpp_dout(dpp, 0) << "ERROR: deleting role name from Role pool: " - << info.name << ": " << cpp_strerror(-ret) << dendl; - } - - // Delete path - if (!info.account_id.empty()) { - librados::Rados& rados = *store->getRados()->get_rados_handle(); - const RGWZoneParams& zone = store->svc()->zone->get_zone_params(); - const rgw_raw_obj& obj = rgwrados::account::get_roles_obj(zone, info.account_id); - ret = rgwrados::roles::remove(dpp, y, rados, obj, info.name); - if (ret < 0) { - ldpp_dout(dpp, 4) << "ERROR: deleting role path from account list: " - << info.path << ": " << cpp_strerror(-ret) << dendl; - } - } else { - oid = info.tenant + get_path_oid_prefix() + info.path + get_info_oid_prefix() + info.id; - ret = rgw_delete_system_obj(dpp, store->svc()->sysobj, pool, oid, nullptr, y); - if (ret < 0) { - ldpp_dout(dpp, 4) << "ERROR: deleting role path from Role pool: " - << info.path << ": " << cpp_strerror(-ret) << dendl; - } - } - return 0; + librados::Rados& rados = *store->getRados()->get_rados_handle(); + RGWServices* svc = store->svc(); + const RGWZoneParams& zone = svc->zone->get_zone_params(); + return rgwrados::role::remove(dpp, y, rados, *svc->sysobj, svc->mdlog, zone, + info.tenant, info.account_id, info.name); } } // namespace rgw::sal diff --git a/src/rgw/driver/rados/rgw_sal_rados.h b/src/rgw/driver/rados/rgw_sal_rados.h index d359f733ab352..0372c5882aa16 100644 --- a/src/rgw/driver/rados/rgw_sal_rados.h +++ b/src/rgw/driver/rados/rgw_sal_rados.h @@ -1164,13 +1164,10 @@ public: RadosRole(RadosStore* _store) : store(_store) {} ~RadosRole() = default; - virtual int store_info(const DoutPrefixProvider *dpp, bool exclusive, optional_yield y) override; - virtual int store_name(const DoutPrefixProvider *dpp, bool exclusive, optional_yield y) override; - virtual int store_path(const DoutPrefixProvider *dpp, bool exclusive, optional_yield y) override; - virtual int read_id(const DoutPrefixProvider *dpp, const std::string& role_name, const std::string& tenant, std::string& role_id, optional_yield y) override; - virtual int read_name(const DoutPrefixProvider *dpp, optional_yield y) override; - virtual int read_info(const DoutPrefixProvider *dpp, optional_yield y) override; - virtual int create(const DoutPrefixProvider *dpp, bool exclusive, const std::string& role_id, optional_yield y) override; - virtual int delete_obj(const DoutPrefixProvider *dpp, optional_yield y) override; + int load_by_name(const DoutPrefixProvider *dpp, optional_yield y) override; + int load_by_id(const DoutPrefixProvider *dpp, optional_yield y) override; + int store_info(const DoutPrefixProvider *dpp, bool exclusive, optional_yield y) override; + int delete_obj(const DoutPrefixProvider *dpp, optional_yield y) override; }; + }} // namespace rgw::sal diff --git a/src/rgw/driver/rados/rgw_service.cc b/src/rgw/driver/rados/rgw_service.cc index 792e4eb65b077..6a177a4acd5ea 100644 --- a/src/rgw/driver/rados/rgw_service.cc +++ b/src/rgw/driver/rados/rgw_service.cc @@ -36,7 +36,7 @@ #include "rgw_otp.h" #include "rgw_sal_rados.h" #include "rgw_user.h" -#include "rgw_role.h" +#include "role.h" #include "rgw_pubsub.h" #include "topic.h" @@ -385,7 +385,8 @@ int RGWCtlDef::init(RGWServices& svc, rgw::sal::Driver* driver, meta.otp = rgwrados::otp::create_metadata_handler( *svc.sysobj, *svc.cls, *svc.mdlog, svc.zone->get_zone_params()); - meta.role = create_role_metadata_handler(*driver, *svc.sysobj); + meta.role = rgwrados::role::create_metadata_handler( + rados, *svc.sysobj, *svc.mdlog, svc.zone->get_zone_params()); meta.account = rgwrados::account::create_metadata_handler( *svc.sysobj, svc.zone->get_zone_params()); meta.group = rgwrados::group::create_metadata_handler( diff --git a/src/rgw/driver/rados/role.cc b/src/rgw/driver/rados/role.cc new file mode 100644 index 0000000000000..1dd0aba6d7e05 --- /dev/null +++ b/src/rgw/driver/rados/role.cc @@ -0,0 +1,720 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab ft=cpp + +/* + * Ceph - scalable distributed file system + * + * Copyright contributors to the Ceph project + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "role.h" + +#include +#include + +#include "common/errno.h" +#include "rgw_common.h" +#include "rgw_metadata.h" +#include "rgw_metadata_lister.h" +#include "rgw_role.h" +#include "rgw_string.h" +#include "rgw_tools.h" +#include "rgw_zone.h" +#include "svc_mdlog.h" + +#include "account.h" +#include "roles.h" + +namespace rgwrados::role { + +// RGWRoleInfo is stored in rados objects named "roles.{id}", +// where ids are assumed to be globally unique +static const std::string oid_prefix = "roles."; +// read_by_name() is enabled by rados objects +// "{tenant}role_names.{name}" for tenant roles, or +// "{account}role_names.{name}" for account roles +constexpr std::string_view name_oid_prefix = "role_names."; +// list() by path/prefix is enabled by rados objects +// "{tenant}role_paths.{path}roles.{id}" for tenant roles. +// see rgwrados::roles::list() for account roles +constexpr std::string_view path_oid_prefix = "role_paths."; + + +static rgw_raw_obj get_id_obj(const RGWZoneParams& zone, + std::string_view id) +{ + return {zone.roles_pool, string_cat_reserve(oid_prefix, id)}; +} + +static int read_info(const DoutPrefixProvider* dpp, optional_yield y, + RGWSI_SysObj& sysobj, const rgw_raw_obj& obj, + RGWRoleInfo& info, ceph::real_time* pmtime, + RGWObjVersionTracker* pobjv, + rgw_cache_entry_info* pcache_info) +{ + bufferlist bl; + std::map attrs; + // "tagging" doesn't start with RGW_ATTR_PREFIX, don't filter it out + constexpr bool raw_attrs = true; + int r = rgw_get_system_obj(&sysobj, obj.pool, obj.oid, bl, pobjv, + pmtime, y, dpp, &attrs, pcache_info, + boost::none, raw_attrs); + if (r < 0) { + return r; + } + + try { + auto p = bl.cbegin(); + decode(info, p); + } catch (const buffer::error&) { + return -EIO; + } + + if (auto i = attrs.find("tagging"); i != attrs.end()) { + try { + using ceph::decode; + auto p = i->second.cbegin(); + decode(info.tags, p); + } catch (const buffer::error&) { + ldpp_dout(dpp, 0) << "ERROR: failed to decode attrs " << info.id << dendl; + return -EIO; + } + } + + return 0; +} + +int read_by_id(const DoutPrefixProvider* dpp, optional_yield y, + RGWSI_SysObj& sysobj, const RGWZoneParams& zone, + std::string_view role_id, RGWRoleInfo& info, + ceph::real_time* pmtime, RGWObjVersionTracker* pobjv, + rgw_cache_entry_info* pcache_info) +{ + const rgw_raw_obj& obj = get_id_obj(zone, role_id); + return read_info(dpp, y, sysobj, obj, info, pmtime, pobjv, pcache_info); +} + +static int write_info(const DoutPrefixProvider* dpp, optional_yield y, + RGWSI_SysObj& sysobj, const RGWZoneParams& zone, + const RGWRoleInfo& info, RGWObjVersionTracker& objv, + ceph::real_time mtime, bool exclusive) +{ + std::map attrs; + if (!info.tags.empty()) { + using ceph::encode; + bufferlist tagbl; + encode(info.tags, tagbl); + attrs.emplace("tagging", std::move(tagbl)); + } + + bufferlist bl; + encode(info, bl); + + const rgw_raw_obj& obj = get_id_obj(zone, info.id); + int r = rgw_put_system_obj(dpp, &sysobj, obj.pool, obj.oid, + bl, exclusive, &objv, mtime, y, &attrs); + if (r < 0) { + ldpp_dout(dpp, 1) << "ERROR: failed to write role obj " << obj + << " with: " << cpp_strerror(r) << dendl; + return r; + } + return 0; +} + +struct IndexObj { + rgw_raw_obj obj; + RGWObjVersionTracker objv; +}; + +static rgw_raw_obj get_name_obj(const RGWZoneParams& zone, + std::string_view tenant, + const rgw_account_id& account, + std::string_view name) +{ + if (account.empty()) { + // use tenant as prefix + std::string oid = string_cat_reserve(tenant, name_oid_prefix, name); + return {zone.roles_pool, std::move(oid)}; + } else { + // names are case-insensitive, so store them in lower case + std::string lower_name{name}; + boost::algorithm::to_lower(lower_name); + // use account id as prefix + std::string oid = string_cat_reserve(account, name_oid_prefix, lower_name); + return {zone.roles_pool, std::move(oid)}; + } +} +static rgw_raw_obj get_name_obj(const RGWZoneParams& zone, + const RGWRoleInfo& info) +{ + return get_name_obj(zone, info.tenant, info.account_id, info.name); +} + +static int write_name(const DoutPrefixProvider* dpp, optional_yield y, + RGWSI_SysObj& sysobj, const std::string& role_id, + IndexObj& index) +{ + RGWNameToId nameToId; + nameToId.obj_id = role_id; + + bufferlist bl; + encode(nameToId, bl); + + return rgw_put_system_obj(dpp, &sysobj, index.obj.pool, index.obj.oid, bl, + true, &index.objv, ceph::real_time(), y); +} + +static int read_name(const DoutPrefixProvider* dpp, optional_yield y, + RGWSI_SysObj& sysobj, IndexObj& name, + RGWNameToId& name_to_id) +{ + bufferlist bl; + int r = rgw_get_system_obj(&sysobj, name.obj.pool, name.obj.oid, + bl, &name.objv, nullptr, y, dpp); + if (r < 0) { + ldpp_dout(dpp, 4) << "failed to read role name object " << name.obj + << " with: " << cpp_strerror(r) << dendl; + return r; + } + + try { + auto p = bl.cbegin(); + decode(name_to_id, p); + } catch (const buffer::error& e) { + ldpp_dout(dpp, 4) << "failed to decode role name object: " + << e.what() << dendl; + return -EIO; + } + return 0; +} + +static int remove_index(const DoutPrefixProvider* dpp, optional_yield y, + RGWSI_SysObj& sysobj, IndexObj& index) +{ + int r = rgw_delete_system_obj(dpp, &sysobj, index.obj.pool, + index.obj.oid, &index.objv, y); + if (r < 0) { + ldpp_dout(dpp, 20) << "WARNING: failed to remove " + << index.obj << " with " << cpp_strerror(r) << dendl; + } + return r; +} + +using NameIndex = std::optional; + +static int remove_index(const DoutPrefixProvider* dpp, optional_yield y, + RGWSI_SysObj& sysobj, NameIndex& index) +{ + if (index) { + return remove_index(dpp, y, sysobj, *index); + } + return 0; +} + + +static rgw_raw_obj get_tenant_path_obj(const RGWZoneParams& zone, + const RGWRoleInfo& info) +{ + std::string oid = string_cat_reserve(info.tenant, path_oid_prefix, + info.path, oid_prefix, info.id); + return {zone.roles_pool, std::move(oid)}; +} + +static int write_tenant_path(const DoutPrefixProvider* dpp, optional_yield y, + RGWSI_SysObj& sysobj, IndexObj& path) +{ + bufferlist bl; + return rgw_put_system_obj(dpp, &sysobj, path.obj.pool, path.obj.oid, bl, + true, &path.objv, ceph::real_time(), y); +} + +static int read_tenant_path(const DoutPrefixProvider* dpp, optional_yield y, + RGWSI_SysObj& sysobj, IndexObj& path) +{ + bufferlist bl; + return rgw_get_system_obj(&sysobj, path.obj.pool, path.obj.oid, + bl, &path.objv, nullptr, y, dpp); +} + +struct AccountIndex { + rgw_raw_obj obj; + std::string_view name; +}; + +static int remove_index(const DoutPrefixProvider* dpp, + optional_yield y, librados::Rados& rados, + const AccountIndex& index) +{ + return roles::remove(dpp, y, rados, index.obj, index.name); +} + +using PathIndex = std::variant; + +static int write_path(const DoutPrefixProvider* dpp, optional_yield y, + librados::Rados& rados, RGWSI_SysObj& sysobj, + const RGWZoneParams& zone, const RGWRoleInfo& info, + PathIndex& index) +{ + if (!info.account_id.empty()) { + // add the new role to its account + AccountIndex path; + path.obj = account::get_roles_obj(zone, info.account_id); + path.name = info.name; + + constexpr bool exclusive = true; + constexpr uint32_t no_limit = std::numeric_limits::max(); + int r = roles::add(dpp, y, rados, path.obj, info, exclusive, no_limit); + if (r < 0) { + ldpp_dout(dpp, 1) << "failed to add role to account " + << path.obj << " with: " << cpp_strerror(r) << dendl; + return r; + } + index = std::move(path); + } else { + // write the new path object + IndexObj path; + path.obj = get_tenant_path_obj(zone, info); + path.objv.generate_new_write_ver(dpp->get_cct()); + + int r = write_tenant_path(dpp, y, sysobj, path); + if (r < 0) { + ldpp_dout(dpp, 1) << "failed to write role path obj " + << path.obj << " with: " << cpp_strerror(r) << dendl; + return r; + } + index = std::move(path); + } + return 0; +} + +static int remove_index(const DoutPrefixProvider* dpp, + optional_yield y, librados::Rados& rados, + RGWSI_SysObj& sysobj, PathIndex& index) +{ + return std::visit(fu2::overload( + [&] (std::monostate&) { return 0; }, + [&] (IndexObj& path) { + return remove_index(dpp, y, sysobj, path); + }, + [&] (AccountIndex& path) { + return remove_index(dpp, y, rados, path); + }), index); +} + +int read_by_name(const DoutPrefixProvider* dpp, optional_yield y, + RGWSI_SysObj& sysobj, const RGWZoneParams& zone, + std::string_view tenant, const rgw_account_id& account, + std::string_view name, RGWRoleInfo& info, + ceph::real_time* pmtime, RGWObjVersionTracker* pobjv, + rgw_cache_entry_info* pcache_info) +{ + IndexObj n; + n.obj = get_name_obj(zone, tenant, account, name); + + RGWNameToId name_to_id; + int r = read_name(dpp, y, sysobj, n, name_to_id); + if (r < 0) { + return r; + } + + return read_by_id(dpp, y, sysobj, zone, name_to_id.obj_id, + info, pmtime, pobjv, pcache_info); +} + +int write(const DoutPrefixProvider* dpp, optional_yield y, + librados::Rados& rados, RGWSI_SysObj& sysobj, RGWSI_MDLog* mdlog, + const RGWZoneParams& zone, const RGWRoleInfo& info, + RGWObjVersionTracker& objv, ceph::real_time mtime, + bool exclusive) +{ + int r = 0; + + // read existing info in case we need to remove its name/path + RGWRoleInfo old; + RGWRoleInfo* old_info = nullptr; + if (!exclusive) { + r = read_by_id(dpp, y, sysobj, zone, info.id, old); + if (r == -ENOENT) { + } else if (r < 0) { + return r; + } else { + old_info = &old; + } + } + + const bool same_name = old_info && + old_info->tenant == info.tenant && + old_info->account_id == info.account_id && + old_info->name == info.name; + const bool same_path = old_info && + old_info->tenant == info.tenant && + old_info->account_id == info.account_id && + old_info->path == info.path; + + NameIndex remove_name; + PathIndex remove_path; + if (old_info) { + if (old_info->id != info.id) { + ldpp_dout(dpp, 1) << "ERROR: can't modify role id" << dendl; + return -EINVAL; + } + if (!same_name && !old_info->name.empty()) { + IndexObj name; + name.obj = get_name_obj(zone, *old_info); + RGWNameToId name_to_id; + r = read_name(dpp, y, sysobj, name, name_to_id); + if (r == -ENOENT) { + // leave remove_name empty + } else if (r < 0) { + return r; + } else if (name_to_id.obj_id == info.id) { + remove_name = std::move(name); + } + } + if (!same_path) { + if (!old_info->account_id.empty()) { + AccountIndex path; + path.obj = account::get_roles_obj(zone, old_info->account_id); + path.name = old_info->name; + remove_path = std::move(path); + } else { + // look up tenant path + IndexObj path; + path.obj = get_tenant_path_obj(zone, *old_info); + r = read_tenant_path(dpp, y, sysobj, path); + if (r == -ENOENT) { + // leave remove_path empty + } else if (r < 0) { + return r; + } else { + remove_path = std::move(path); + } + } + } + } // old_info + + // write the new name object, fail on conflict + NameIndex new_name; + if (!same_name && !info.name.empty()) { + IndexObj name; + name.obj = get_name_obj(zone, info); + name.objv.generate_new_write_ver(dpp->get_cct()); + + r = write_name(dpp, y, sysobj, info.id, name); + if (r < 0) { + ldpp_dout(dpp, 1) << "failed to write name obj " + << name.obj << " with: " << cpp_strerror(r) << dendl; + return r; + } + new_name = std::move(name); + } + + // check for path conflict + PathIndex new_path; + if (!same_path) { + r = write_path(dpp, y, rados, sysobj, zone, info, new_path); + if (r < 0) { + // roll back new name object + std::ignore = remove_index(dpp, y, sysobj, new_name); + return r; + } + } + + // write info by id + r = write_info(dpp, y, sysobj, zone, info, objv, mtime, exclusive); + if (r < 0) { + // roll back the new name/path indices + std::ignore = remove_index(dpp, y, sysobj, new_name); + std::ignore = remove_index(dpp, y, rados, sysobj, new_path); + return r; + } + + // remove the old name/path indices + std::ignore = remove_index(dpp, y, sysobj, remove_name); + std::ignore = remove_index(dpp, y, rados, sysobj, remove_path); + + // record in the mdlog on success + if (mdlog) { + return mdlog->complete_entry(dpp, y, "roles", info.id, &objv); + } + return 0; +} + +static int remove_by_id(const DoutPrefixProvider* dpp, optional_yield y, + librados::Rados& rados, RGWSI_SysObj& sysobj, + RGWSI_MDLog* mdlog, const RGWZoneParams& zone, + std::string_view role_id) +{ + const rgw_raw_obj& obj = get_id_obj(zone, role_id); + + RGWRoleInfo info; + int r = read_info(dpp, y, sysobj, obj, info, + nullptr, &info.objv_tracker, nullptr); + if (r < 0) { + return r; + } + + // delete role info + r = rgw_delete_system_obj(dpp, &sysobj, obj.pool, obj.oid, + &info.objv_tracker, y); + if (r < 0) { + ldpp_dout(dpp, 1) << "ERROR: failed to remove role " + << info.id << " with: " << cpp_strerror(r) << dendl; + return r; + } + + // delete the name object + if (!info.name.empty()) { + IndexObj name; + name.obj = get_name_obj(zone, info); + std::ignore = remove_index(dpp, y, sysobj, name); + } + + // delete the path object + if (!info.account_id.empty()) { + AccountIndex path; + path.obj = account::get_roles_obj(zone, info.account_id); + path.name = info.name; + std::ignore = remove_index(dpp, y, rados, path); + } else { + IndexObj path; + path.obj = get_tenant_path_obj(zone, info); + std::ignore = remove_index(dpp, y, sysobj, path); + } + + // record in the mdlog on success + if (mdlog) { + return mdlog->complete_entry(dpp, y, "roles", info.id, &info.objv_tracker); + } + return 0; +} + +int remove(const DoutPrefixProvider* dpp, optional_yield y, + librados::Rados& rados, RGWSI_SysObj& sysobj, RGWSI_MDLog* mdlog, + const RGWZoneParams& zone, std::string_view tenant, + const rgw_account_id& account, std::string_view name) +{ + IndexObj n; + n.obj = get_name_obj(zone, tenant, account, name); + RGWNameToId name_to_id; + + int r = read_name(dpp, y, sysobj, n, name_to_id); + if (r < 0) { + return r; + } + + return remove_by_id(dpp, y, rados, sysobj, mdlog, zone, name_to_id.obj_id); +} + + +int list_tenant(const DoutPrefixProvider* dpp, optional_yield y, + RGWSI_SysObj& sysobj, const RGWZoneParams& zone, + std::string_view tenant, const std::string& marker, + int max_items, std::string_view path_prefix, + std::vector& roles, std::string& next_marker) +{ + // List all roles if path prefix is empty + std::string prefix; + if (!path_prefix.empty()) { + prefix = string_cat_reserve(tenant, path_oid_prefix, path_prefix); + } else { + prefix = string_cat_reserve(tenant, path_oid_prefix, "/"); + } + + auto pool = sysobj.get_pool(zone.roles_pool); + auto listing = pool.op(); + int r = listing.init(dpp, marker, prefix); + if (r < 0) { + return r; + } + + std::vector oids; + bool truncated = false; + r = listing.get_next(dpp, max_items, &oids, &truncated); + if (r < 0) { + return r; + } + + for (auto& oid : oids) { + // remove the entire prefix + oid.erase(0, prefix.size()); + // verify that the entire oid_prefix is still present (path_prefix may have + // matched part of it) + size_t pos = oid.rfind(oid_prefix); + if (pos == std::string::npos) { + continue; + } + // after trimming the oid_prefix, we should be left with just the role id + oid.erase(0, pos + oid_prefix.size()); + + RGWRoleInfo info; + r = read_by_id(dpp, y, sysobj, zone, oid, info, nullptr, nullptr, nullptr); + if (r == -ENOENT) { + continue; // ok, listing race with deletion + } + if (r < 0) { + return r; + } + roles.push_back(std::move(info)); + } + + if (truncated) { + listing.get_marker(&next_marker); + } + return 0; +} + + +class MetadataObject : public RGWMetadataObject { + RGWRoleInfo info; +public: + MetadataObject(const RGWRoleInfo& info, const obj_version& v, real_time m) + : RGWMetadataObject(v, m), info(info) {} + + void dump(Formatter *f) const override { + info.dump(f); + } + + RGWRoleInfo& get_role_info() { + return info; + } +}; + +class MetadataLister : public RGWMetadataLister { + public: + using RGWMetadataLister::RGWMetadataLister; + + virtual void filter_transform(std::vector& oids, + std::list& keys) { + // remove the oid prefix from keys + constexpr auto trim = [] (const std::string& oid) { + return oid.substr(oid_prefix.size()); + }; + std::transform(oids.begin(), oids.end(), + std::back_inserter(keys), + trim); + } +}; + +class MetadataHandler : public RGWMetadataHandler { + librados::Rados& rados; + RGWSI_SysObj& sysobj; + RGWSI_MDLog& mdlog; + const RGWZoneParams& zone; + public: + MetadataHandler(librados::Rados& rados, RGWSI_SysObj& sysobj, + RGWSI_MDLog& mdlog, const RGWZoneParams& zone) + : rados(rados), sysobj(sysobj), mdlog(mdlog), zone(zone) {} + + std::string get_type() final { return "roles"; } + + RGWMetadataObject* get_meta_obj(JSONObj *jo, + const obj_version& objv, + const ceph::real_time& mtime) override + { + RGWRoleInfo info; + + try { + info.decode_json(jo); + } catch (JSONDecoder:: err& e) { + return nullptr; + } + + return new MetadataObject(info, objv, mtime); + } + + int get(std::string& entry, RGWMetadataObject** obj, + optional_yield y, const DoutPrefixProvider* dpp) override + { + RGWRoleInfo info; + int ret = read_by_id(dpp, y, sysobj, zone, entry, info, + &info.mtime, &info.objv_tracker); + if (ret < 0) { + return ret; + } + + *obj = new MetadataObject(info, info.objv_tracker.read_version, info.mtime); + return 0; + } + + int put(std::string& entry, RGWMetadataObject* obj, + RGWObjVersionTracker& objv_tracker, + optional_yield y, const DoutPrefixProvider* dpp, + RGWMDLogSyncType type, bool from_remote_zone) override + { + auto robj = static_cast(obj); + auto& info = robj->get_role_info(); + info.mtime = robj->get_mtime(); + + constexpr bool exclusive = false; + int ret = write(dpp, y, rados, sysobj, &mdlog, zone, info, + info.objv_tracker, info.mtime, exclusive); + return ret < 0 ? ret : STATUS_APPLIED; + } + + int remove(std::string& entry, RGWObjVersionTracker& objv_tracker, + optional_yield y, const DoutPrefixProvider *dpp) override + { + return remove_by_id(dpp, y, rados, sysobj, &mdlog, zone, entry); + } + + int mutate(const std::string& entry, const ceph::real_time& mtime, + RGWObjVersionTracker* objv_tracker, optional_yield y, + const DoutPrefixProvider* dpp, RGWMDLogStatus op_type, + std::function f) override + { + return -ENOTSUP; // unused + } + + int list_keys_init(const DoutPrefixProvider* dpp, + const std::string& marker, + void** phandle) override + { + const auto& pool = zone.roles_pool; + auto lister = std::make_unique(sysobj.get_pool(pool)); + int ret = lister->init(dpp, marker, oid_prefix); + if (ret < 0) { + return ret; + } + *phandle = lister.release(); // release ownership + return 0; + } + + int list_keys_next(const DoutPrefixProvider* dpp, + void* handle, int max, + std::list& keys, + bool* truncated) override + { + auto lister = static_cast(handle); + return lister->get_next(dpp, max, keys, truncated); + } + + void list_keys_complete(void *handle) override + { + delete static_cast(handle); + } + + std::string get_marker(void *handle) override + { + auto lister = static_cast(handle); + return lister->get_marker(); + } +}; + + +auto create_metadata_handler(librados::Rados& rados, + RGWSI_SysObj& sysobj, + RGWSI_MDLog& mdlog, + const RGWZoneParams& zone) + -> std::unique_ptr +{ + return std::make_unique(rados, sysobj, mdlog, zone); +} + +} // rgwrados::role diff --git a/src/rgw/driver/rados/role.h b/src/rgw/driver/rados/role.h new file mode 100644 index 0000000000000..7dc721c712123 --- /dev/null +++ b/src/rgw/driver/rados/role.h @@ -0,0 +1,81 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab ft=cpp + +/* + * Ceph - scalable distributed file system + * + * Copyright contributors to the Ceph project + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#pragma once + +#include +#include +#include +#include "include/rados/librados_fwd.hpp" +#include "common/ceph_time.h" + +class DoutPrefixProvider; +class optional_yield; +struct rgw_account_id; +struct rgw_cache_entry_info; +class RGWMetadataHandler; +class RGWObjVersionTracker; +struct RGWRoleInfo; +class RGWSI_MDLog; +class RGWSI_SysObj; +class RGWZoneParams; + +namespace rgwrados::role { + +/// Read role info by id. +int read_by_id(const DoutPrefixProvider* dpp, optional_yield y, + RGWSI_SysObj& sysobj, const RGWZoneParams& zone, + std::string_view role_id, RGWRoleInfo& info, + ceph::real_time* pmtime = nullptr, + RGWObjVersionTracker* pobjv = nullptr, + rgw_cache_entry_info* pcache_info = nullptr); + +/// Read role info by name. +int read_by_name(const DoutPrefixProvider* dpp, optional_yield y, + RGWSI_SysObj& sysobj, const RGWZoneParams& zone, + std::string_view tenant, const rgw_account_id& account, + std::string_view name, RGWRoleInfo& info, + ceph::real_time* pmtime = nullptr, + RGWObjVersionTracker* pobjv = nullptr, + rgw_cache_entry_info* pcache_info = nullptr); + +/// Write or overwrite role info and update its name/path objects. +int write(const DoutPrefixProvider* dpp, optional_yield y, + librados::Rados& rados, RGWSI_SysObj& sysobj, RGWSI_MDLog* mdlog, + const RGWZoneParams& zone, const RGWRoleInfo& info, + RGWObjVersionTracker& objv, ceph::real_time mtime, + bool exclusive); + +/// Remove a role by name, including its name/path objects. +int remove(const DoutPrefixProvider* dpp, optional_yield y, + librados::Rados& rados, RGWSI_SysObj& sysobj, RGWSI_MDLog* mdlog, + const RGWZoneParams& zone, std::string_view tenant, + const rgw_account_id& account, std::string_view name); + +/// Return a paginated listing of roles for the given tenant. +int list_tenant(const DoutPrefixProvider* dpp, optional_yield y, + RGWSI_SysObj& sysobj, const RGWZoneParams& zone, + std::string_view tenant, const std::string& marker, + int max_items, std::string_view path_prefix, + std::vector& roles, std::string& next_marker); + +/// Role metadata handler factory. +auto create_metadata_handler(librados::Rados& rados, + RGWSI_SysObj& sysobj, + RGWSI_MDLog& mdlog, + const RGWZoneParams& zone) + -> std::unique_ptr; + +} // rgwrados::role diff --git a/src/rgw/rgw_admin.cc b/src/rgw/rgw_admin.cc index 6e894ae2d24e9..d1b041f2423fe 100644 --- a/src/rgw/rgw_admin.cc +++ b/src/rgw/rgw_admin.cc @@ -6855,7 +6855,7 @@ int main(int argc, const char **argv) } std::unique_ptr role = driver->get_role(role_name, tenant, account_id, path, assume_role_doc, description, max_session_duration); - ret = role->create(dpp(), true, "", null_yield); + ret = role->create(dpp(), "", null_yield); if (ret < 0) { return -ret; } @@ -6884,7 +6884,7 @@ int main(int argc, const char **argv) return -EINVAL; } std::unique_ptr role = driver->get_role(role_name, tenant, account_id); - ret = role->get(dpp(), null_yield); + ret = role->load_by_name(dpp(), null_yield); if (ret < 0) { return -ret; } @@ -6914,12 +6914,13 @@ int main(int argc, const char **argv) } std::unique_ptr role = driver->get_role(role_name, tenant, account_id); - ret = role->get(dpp(), null_yield); + ret = role->load_by_name(dpp(), null_yield); if (ret < 0) { return -ret; } role->update_trust_policy(assume_role_doc); - ret = role->update(dpp(), null_yield); + constexpr bool exclusive = false; + ret = role->store_info(dpp(), exclusive, null_yield); if (ret < 0) { return -ret; } @@ -7009,12 +7010,13 @@ int main(int argc, const char **argv) } std::unique_ptr role = driver->get_role(role_name, tenant, account_id); - ret = role->get(dpp(), null_yield); + ret = role->load_by_name(dpp(), null_yield); if (ret < 0) { return -ret; } role->set_perm_policy(policy_name, perm_policy_doc); - ret = role->update(dpp(), null_yield); + constexpr bool exclusive = false; + ret = role->store_info(dpp(), exclusive, null_yield); if (ret < 0) { return -ret; } @@ -7028,7 +7030,7 @@ int main(int argc, const char **argv) return -EINVAL; } std::unique_ptr role = driver->get_role(role_name, tenant, account_id); - ret = role->get(dpp(), null_yield); + ret = role->load_by_name(dpp(), null_yield); if (ret < 0) { return -ret; } @@ -7048,7 +7050,7 @@ int main(int argc, const char **argv) return -EINVAL; } std::unique_ptr role = driver->get_role(role_name, tenant, account_id); - int ret = role->get(dpp(), null_yield); + int ret = role->load_by_name(dpp(), null_yield); if (ret < 0) { return -ret; } @@ -7072,7 +7074,7 @@ int main(int argc, const char **argv) return -EINVAL; } std::unique_ptr role = driver->get_role(role_name, tenant, account_id); - ret = role->get(dpp(), null_yield); + ret = role->load_by_name(dpp(), null_yield); if (ret < 0) { return -ret; } @@ -7080,7 +7082,8 @@ int main(int argc, const char **argv) if (ret < 0) { return -ret; } - ret = role->update(dpp(), null_yield); + constexpr bool exclusive = false; + ret = role->store_info(dpp(), exclusive, null_yield); if (ret < 0) { return -ret; } @@ -7109,7 +7112,7 @@ int main(int argc, const char **argv) } std::unique_ptr role = driver->get_role(role_name, tenant, account_id); - ret = role->get(dpp(), null_yield); + ret = role->load_by_id(dpp(), null_yield); if (ret < 0) { return -ret; } @@ -7124,7 +7127,8 @@ int main(int argc, const char **argv) cout << "That managed policy is already attached." << std::endl; return EEXIST; } - ret = role->update(dpp(), null_yield); + constexpr bool exclusive = false; + ret = role->store_info(dpp(), exclusive, null_yield); if (ret < 0) { return -ret; } @@ -7143,7 +7147,7 @@ int main(int argc, const char **argv) } std::unique_ptr role = driver->get_role(role_name, tenant, account_id); - ret = role->get(dpp(), null_yield); + ret = role->load_by_id(dpp(), null_yield); if (ret < 0) { return -ret; } @@ -7156,7 +7160,8 @@ int main(int argc, const char **argv) } policies.arns.erase(i); - ret = role->update(dpp(), null_yield); + constexpr bool exclusive = false; + ret = role->store_info(dpp(), exclusive, null_yield); if (ret < 0) { return -ret; } @@ -7170,7 +7175,7 @@ int main(int argc, const char **argv) return EINVAL; } std::unique_ptr role = driver->get_role(role_name, tenant, account_id); - ret = role->get(dpp(), null_yield); + ret = role->load_by_id(dpp(), null_yield); if (ret < 0) { return -ret; } @@ -7186,7 +7191,7 @@ int main(int argc, const char **argv) } std::unique_ptr role = driver->get_role(role_name, tenant, account_id); - ret = role->get(dpp(), null_yield); + ret = role->load_by_name(dpp(), null_yield); if (ret < 0) { return -ret; } @@ -7195,7 +7200,8 @@ int main(int argc, const char **argv) ret = -EINVAL; return ret; } - ret = role->update(dpp(), null_yield); + constexpr bool exclusive = false; + ret = role->store_info(dpp(), exclusive, null_yield); if (ret < 0) { return -ret; } diff --git a/src/rgw/rgw_rest_iam.h b/src/rgw/rgw_rest_iam.h index 00f6ff7dfc4aa..5a4a8329b2b5d 100644 --- a/src/rgw/rgw_rest_iam.h +++ b/src/rgw/rgw_rest_iam.h @@ -83,7 +83,7 @@ int retry_raced_role_write(const DoutPrefixProvider* dpp, optional_yield y, int r = f(); for (int i = 0; i < 10 && r == -ECANCELED; ++i) { role->get_objv_tracker().clear(); - r = role->get_by_id(dpp, y); + r = role->load_by_id(dpp, y); if (r >= 0) { r = f(); } diff --git a/src/rgw/rgw_rest_role.cc b/src/rgw/rgw_rest_role.cc index b3d6b42ae6b9b..a3733c175cc3c 100644 --- a/src/rgw/rgw_rest_role.cc +++ b/src/rgw/rgw_rest_role.cc @@ -114,7 +114,7 @@ static int load_role(const DoutPrefixProvider* dpp, optional_yield y, rgw::ARN& resource, std::string& message) { role = driver->get_role(name, tenant, account_id); - const int r = role->get(dpp, y); + const int r = role->load_by_name(dpp, y); if (r == -ENOENT) { message = "No such RoleName in the tenant"; return -ERR_NO_ROLE_FOUND; @@ -312,7 +312,7 @@ void RGWCreateRole::execute(optional_yield y) ldpp_dout(this, 0) << "role_id decoded from master zonegroup response is " << role_id << dendl; } - op_ret = role->create(s, true, role_id, y); + op_ret = role->create(s, role_id, y); if (op_ret == -EEXIST) { if (site.is_meta_master()) { op_ret = -ERR_ROLE_EXISTS; @@ -489,7 +489,8 @@ void RGWModifyRoleTrustPolicy::execute(optional_yield y) op_ret = retry_raced_role_write(this, y, role.get(), [this, y] { role->update_trust_policy(trust_policy); - return role->update(this, y); + constexpr bool exclusive = false; + return role->store_info(this, exclusive, y); }); s->formatter->open_object_section("UpdateAssumeRolePolicyResponse"); @@ -625,7 +626,8 @@ void RGWPutRolePolicy::execute(optional_yield y) op_ret = retry_raced_role_write(this, y, role.get(), [this, y] { role->set_perm_policy(policy_name, perm_policy); - return role->update(this, y); + constexpr bool exclusive = false; + return role->store_info(this, exclusive, y); }); if (op_ret == 0) { @@ -766,7 +768,8 @@ void RGWDeleteRolePolicy::execute(optional_yield y) return -ERR_NO_SUCH_ENTITY; } if (r == 0) { - r = role->update(this, y); + constexpr bool exclusive = false; + r = role->store_info(this, exclusive, y); } return r; }); @@ -833,7 +836,8 @@ void RGWTagRole::execute(optional_yield y) [this, y] { int r = role->set_tags(this, tags); if (r == 0) { - r = role->update(this, y); + constexpr bool exclusive = false; + r = role->store_info(this, exclusive, y); } return r; }); @@ -940,7 +944,8 @@ void RGWUntagRole::execute(optional_yield y) op_ret = retry_raced_role_write(this, y, role.get(), [this, y] { role->erase_tags(untag); - return role->update(this, y); + constexpr bool exclusive = false; + return role->store_info(this, exclusive, y); }); if (op_ret == 0) { @@ -1009,15 +1014,18 @@ void RGWUpdateRole::execute(optional_yield y) return -EINVAL; } - return role->update(this, y); + constexpr bool exclusive = false; + return role->store_info(this, exclusive, y); }); - s->formatter->open_object_section("UpdateRoleResponse"); - s->formatter->open_object_section("UpdateRoleResult"); - s->formatter->open_object_section("ResponseMetadata"); - s->formatter->dump_string("RequestId", s->trans_id); - s->formatter->close_section(); - s->formatter->close_section(); + if (op_ret == 0) { + s->formatter->open_object_section("UpdateRoleResponse"); + s->formatter->open_object_section("UpdateRoleResult"); + s->formatter->open_object_section("ResponseMetadata"); + s->formatter->dump_string("RequestId", s->trans_id); + s->formatter->close_section(); + s->formatter->close_section(); + } } static bool validate_policy_arn(const std::string& arn, std::string& err) @@ -1127,7 +1135,8 @@ void RGWAttachRolePolicy_IAM::execute(optional_yield y) if (!policies.arns.insert(policy_arn).second) { return 0; } - return role->update(this, y); + constexpr bool exclusive = false; + return role->store_info(this, exclusive, y); }); if (op_ret == 0) { @@ -1217,7 +1226,9 @@ void RGWDetachRolePolicy_IAM::execute(optional_yield y) return -ERR_NO_SUCH_ENTITY; } policies.arns.erase(p); - return role->update(this, y); + + constexpr bool exclusive = false; + return role->store_info(this, exclusive, y); }); if (op_ret == 0) { diff --git a/src/rgw/rgw_rest_role.h b/src/rgw/rgw_rest_role.h index b7c662c02c66f..97f9deafeb626 100644 --- a/src/rgw/rgw_rest_role.h +++ b/src/rgw/rgw_rest_role.h @@ -85,7 +85,6 @@ class RGWListRoles : public RGWRestRole { std::string path_prefix; std::string marker; int max_items = 100; - std::string next_marker; public: RGWListRoles() : RGWRestRole(rgw::IAM::iamListRoles, RGW_CAP_READ) {} int init_processing(optional_yield y) override; diff --git a/src/rgw/rgw_rest_s3.cc b/src/rgw/rgw_rest_s3.cc index 8da355dd8162c..4a50baf1cb201 100644 --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@ -6537,7 +6537,7 @@ rgw::auth::s3::STSEngine::authenticate( rgw::auth::RoleApplier::TokenAttrs t_attrs; if (! token.roleId.empty()) { std::unique_ptr role = driver->get_role(token.roleId); - if (role->get_by_id(dpp, y) < 0) { + if (role->load_by_id(dpp, y) < 0) { return result_t::deny(-EPERM); } r.id = token.roleId; diff --git a/src/rgw/rgw_rest_sts.cc b/src/rgw/rgw_rest_sts.cc index dbe4994cfa528..f2bd9429a5538 100644 --- a/src/rgw/rgw_rest_sts.cc +++ b/src/rgw/rgw_rest_sts.cc @@ -496,7 +496,7 @@ WebTokenEngine::authenticate( const DoutPrefixProvider* dpp, } std::unique_ptr role = driver->get_role(role_name, role_tenant, role_account); - int ret = role->get(dpp, y); + int ret = role->load_by_name(dpp, y); if (ret < 0) { ldpp_dout(dpp, 0) << "Role not found: name:" << role_name << " tenant: " << role_tenant << dendl; return result_t::deny(-EACCES); diff --git a/src/rgw/rgw_role.cc b/src/rgw/rgw_role.cc index c85f29d903572..d7070e4785e2b 100644 --- a/src/rgw/rgw_role.cc +++ b/src/rgw/rgw_role.cc @@ -131,9 +131,6 @@ void RGWRoleInfo::decode_json(JSONObj *obj) namespace rgw::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::"; RGWRole::RGWRole(std::string name, @@ -168,31 +165,6 @@ 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; -} - bool RGWRole::validate_max_session_duration(const DoutPrefixProvider* dpp) { if (info.max_session_duration < SESSION_DURATION_MIN || @@ -241,16 +213,46 @@ void RGWRole::extract_name_tenant(const std::string& str) { } } -int RGWRole::update(const DoutPrefixProvider *dpp, optional_yield y) +int RGWRole::create(const DoutPrefixProvider *dpp, const std::string& role_id, 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; + if (! validate_input(dpp)) { + return -EINVAL; } - return 0; + if (!role_id.empty()) { + info.id = role_id; + } + + if (info.id.empty()) { + /* create unique id */ + uuid_d new_uuid; + char uuid_str[37]; + new_uuid.generate_random(); + new_uuid.print(uuid_str); + info.id = uuid_str; + } + + //arn + std::string_view account = !info.account_id.empty() ? info.account_id : info.tenant; + info.arn = string_cat_reserve(role_arn_prefix, account, ":role", info.path, info.name); + + if (info.creation_date.empty()) { + // Creation time + real_clock::time_point t = real_clock::now(); + + struct timeval tv; + real_clock::to_timeval(t, tv); + + char buf[30]; + struct tm result; + gmtime_r(&tv.tv_sec, &result); + strftime(buf,30,"%Y-%m-%dT%H:%M:%S", &result); + sprintf(buf + strlen(buf),".%03dZ",(int)tv.tv_usec/1000); + info.creation_date.assign(buf, strlen(buf)); + } + + constexpr bool exclusive = true; + return store_info(dpp, exclusive, y); } void RGWRole::set_perm_policy(const string& policy_name, const string& perm_policy) @@ -334,203 +336,4 @@ void RGWRole::update_max_session_duration(const std::string& max_session_duratio } } -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; -} - } // namespace rgw::sal - - -class RGWRoleMetadataObject: public RGWMetadataObject { - RGWRoleInfo info; -public: - RGWRoleMetadataObject(const RGWRoleInfo& info, const obj_version& v, real_time m) - : RGWMetadataObject(v, m), info(info) {} - - void dump(Formatter *f) const override { - info.dump(f); - } - - RGWRoleInfo& get_role_info() { - return info; - } -}; - -class RGWRoleMetadataHandler: public RGWMetadataHandler { - rgw::sal::Driver& driver; - RGWSI_SysObj& sysobj; - public: - RGWRoleMetadataHandler(rgw::sal::Driver& driver, RGWSI_SysObj& sysobj) - : driver(driver), sysobj(sysobj) {} - - std::string get_type() final { return "roles"; } - - RGWMetadataObject *get_meta_obj(JSONObj *jo, - const obj_version& objv, - const ceph::real_time& mtime); - - int get(std::string& entry, RGWMetadataObject** obj, optional_yield y, - const DoutPrefixProvider *dpp) override; - int put(std::string& entry, RGWMetadataObject* obj, - RGWObjVersionTracker& objv_tracker, - optional_yield y, const DoutPrefixProvider* dpp, - RGWMDLogSyncType type, bool from_remote_zone) override; - int remove(std::string& entry, RGWObjVersionTracker& objv_tracker, - optional_yield y, const DoutPrefixProvider *dpp) override; - - int mutate(const std::string& entry, const ceph::real_time& mtime, - RGWObjVersionTracker* objv_tracker, optional_yield y, - const DoutPrefixProvider* dpp, RGWMDLogStatus op_type, - std::function f) override; - - int list_keys_init(const DoutPrefixProvider* dpp, const std::string& marker, - void** phandle) override; - int list_keys_next(const DoutPrefixProvider* dpp, void* handle, int max, - std::list& keys, bool* truncated) override; - void list_keys_complete(void *handle) override; - std::string get_marker(void *handle) override; -}; - -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); -} - -int RGWRoleMetadataHandler::get(std::string& entry, RGWMetadataObject **obj, - optional_yield y, const DoutPrefixProvider *dpp) -{ - std::unique_ptr role = driver.get_role(entry); - int ret = role->read_info(dpp, y); - if (ret < 0) { - return ret; - } - - const RGWRoleInfo& info = role->get_info(); - RGWObjVersionTracker objv_tracker = role->get_objv_tracker(); - real_time mtime = role->get_mtime(); - - *obj = new RGWRoleMetadataObject(info, objv_tracker.read_version, mtime); - - return 0; -} - -int RGWRoleMetadataHandler::put(std::string& entry, RGWMetadataObject *obj, - RGWObjVersionTracker& objv_tracker, - optional_yield y, const DoutPrefixProvider *dpp, - RGWMDLogSyncType type, bool from_remote_zone) -{ - auto robj = static_cast(obj); - auto& info = robj->get_role_info(); - auto mtime = robj->get_mtime(); - info.mtime = mtime; - - std::unique_ptr 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::remove(std::string& entry, - RGWObjVersionTracker& objv_tracker, - optional_yield y, - const DoutPrefixProvider *dpp) -{ - std::unique_ptr 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); -} - -int RGWRoleMetadataHandler::mutate(const std::string& entry, const ceph::real_time& mtime, - RGWObjVersionTracker* objv_tracker, optional_yield y, - const DoutPrefixProvider* dpp, RGWMDLogStatus op_type, - std::function f) -{ - return -ENOTSUP; // unused -} - -class RoleLister : public RGWMetadataLister { - public: - using RGWMetadataLister::RGWMetadataLister; - - virtual void filter_transform(std::vector& oids, - std::list& keys) { - // remove the oid prefix from keys - constexpr auto trim = [] (const std::string& oid) { - return oid.substr(rgw::sal::RGWRole::role_oid_prefix.size()); - }; - std::transform(oids.begin(), oids.end(), - std::back_inserter(keys), - trim); - } -}; - -int RGWRoleMetadataHandler::list_keys_init(const DoutPrefixProvider* dpp, - const std::string& marker, - void** phandle) -{ - auto svc_zone = sysobj.get_zone_svc(); - const auto& pool = svc_zone->get_zone_params().roles_pool; - auto lister = std::make_unique(sysobj.get_pool(pool)); - int ret = lister->init(dpp, marker, rgw::sal::RGWRole::role_oid_prefix); - if (ret < 0) { - return ret; - } - *phandle = lister.release(); // release ownership - return 0; -} - -int RGWRoleMetadataHandler::list_keys_next(const DoutPrefixProvider* dpp, - void* handle, int max, - std::list& keys, - bool* truncated) -{ - auto lister = static_cast(handle); - return lister->get_next(dpp, max, keys, truncated); -} - -void RGWRoleMetadataHandler::list_keys_complete(void *handle) -{ - delete static_cast(handle); -} - -std::string RGWRoleMetadataHandler::get_marker(void *handle) -{ - auto lister = static_cast(handle); - return lister->get_marker(); -} - - -auto create_role_metadata_handler(rgw::sal::Driver& driver, - RGWSI_SysObj& sysobj) - -> std::unique_ptr -{ - return std::make_unique(driver, sysobj); -} diff --git a/src/rgw/rgw_role.h b/src/rgw/rgw_role.h index eae42a752fb17..081259ceaa4db 100644 --- a/src/rgw/rgw_role.h +++ b/src/rgw/rgw_role.h @@ -30,7 +30,6 @@ struct RGWRoleInfo // TODO: move to rgw_common.h std::string description; uint64_t max_session_duration = 0; std::multimap tags; - std::map attrs; RGWObjVersionTracker objv_tracker; ceph::real_time mtime; rgw_account_id account_id; @@ -89,9 +88,6 @@ namespace rgw::sal { class RGWRole { public: - static const std::string role_name_oid_prefix; - static const std::string role_oid_prefix; - static const std::string role_path_oid_prefix; static const std::string role_arn_prefix; static constexpr int MAX_ROLE_NAME_LEN = 64; static constexpr int MAX_PATH_NAME_LEN = 512; @@ -100,12 +96,6 @@ public: protected: RGWRoleInfo info; public: - virtual int store_info(const DoutPrefixProvider *dpp, bool exclusive, optional_yield y) = 0; - virtual int store_name(const DoutPrefixProvider *dpp, bool exclusive, optional_yield y) = 0; - virtual int store_path(const DoutPrefixProvider *dpp, bool exclusive, optional_yield y) = 0; - virtual int read_id(const DoutPrefixProvider *dpp, const std::string& role_name, const std::string& tenant, std::string& role_id, optional_yield y) = 0; - virtual int read_name(const DoutPrefixProvider *dpp, optional_yield y) = 0; - virtual int read_info(const DoutPrefixProvider *dpp, optional_yield y) = 0; bool validate_max_session_duration(const DoutPrefixProvider* dpp); bool validate_input(const DoutPrefixProvider* dpp); void extract_name_tenant(const std::string& str); @@ -127,6 +117,12 @@ public: virtual ~RGWRole() = default; + // virtual interface + virtual int load_by_name(const DoutPrefixProvider *dpp, optional_yield y) = 0; + virtual int load_by_id(const DoutPrefixProvider *dpp, optional_yield y) = 0; + virtual int store_info(const DoutPrefixProvider *dpp, bool exclusive, optional_yield y) = 0; + virtual int delete_obj(const DoutPrefixProvider *dpp, optional_yield y) = 0; + const std::string& get_id() const { return info.id; } const std::string& get_name() const { return info.name; } const std::string& get_tenant() const { return info.tenant; } @@ -138,17 +134,12 @@ public: RGWObjVersionTracker& get_objv_tracker() { return info.objv_tracker; } const RGWObjVersionTracker& get_objv_tracker() const { return info.objv_tracker; } const real_time& get_mtime() const { return info.mtime; } - std::map& get_attrs() { return info.attrs; } RGWRoleInfo& get_info() { return info; } void set_id(const std::string& id) { this->info.id = id; } void set_mtime(const real_time& mtime) { this->info.mtime = mtime; } - virtual int create(const DoutPrefixProvider *dpp, bool exclusive, const std::string &role_id, optional_yield y) = 0; - virtual int delete_obj(const DoutPrefixProvider *dpp, optional_yield y) = 0; - int get(const DoutPrefixProvider *dpp, optional_yield y); - int get_by_id(const DoutPrefixProvider *dpp, optional_yield y); - int update(const DoutPrefixProvider *dpp, optional_yield y); + int create(const DoutPrefixProvider *dpp, const std::string &role_id, optional_yield y); void update_trust_policy(std::string& trust_policy); void set_perm_policy(const std::string& policy_name, const std::string& perm_policy); std::vector get_role_policy_names(); @@ -158,18 +149,6 @@ public: boost::optional> get_tags(); void erase_tags(const std::vector& tagKeys); void update_max_session_duration(const std::string& max_session_duration_str); - - static const std::string& get_names_oid_prefix(); - static const std::string& get_info_oid_prefix(); - static const std::string& get_path_oid_prefix(); }; } // namespace rgw::sal - - -class RGWMetadataHandler; -class RGWSI_SysObj; - -auto create_role_metadata_handler(rgw::sal::Driver& driver, - RGWSI_SysObj& sysobj) - -> std::unique_ptr; diff --git a/src/rgw/rgw_sts.cc b/src/rgw/rgw_sts.cc index f879e0f45c19d..7e8e37b3419d0 100644 --- a/src/rgw/rgw_sts.cc +++ b/src/rgw/rgw_sts.cc @@ -300,7 +300,7 @@ std::tuple STSService::getRoleInfo(const DoutPrefixProv } std::unique_ptr role = driver->get_role(roleName, tenant, account); - if (int ret = role->get(dpp, y); ret < 0) { + if (int ret = role->load_by_name(dpp, y); ret < 0) { if (ret == -ENOENT) { ldpp_dout(dpp, 0) << "Role doesn't exist: " << roleName << dendl; ret = -ERR_NO_ROLE_FOUND; -- 2.39.5