From 10ef9b967435dda86dfa19a29fe6420d7dbb0cc0 Mon Sep 17 00:00:00 2001 From: Casey Bodley Date: Wed, 1 Nov 2023 18:27:42 -0400 Subject: [PATCH] rgw: add /admin/account rest apis Signed-off-by: Casey Bodley (cherry picked from commit cce372dc2ebd2b0d7bdb06b930fcc35ad27147d1) --- src/rgw/CMakeLists.txt | 1 + src/rgw/rgw_appmain.cc | 2 + src/rgw/rgw_common.cc | 1 + src/rgw/rgw_common.h | 1 + src/rgw/rgw_rest_account.cc | 241 ++++++++++++++++++++++++++++++++++++ src/rgw/rgw_rest_account.h | 46 +++++++ 6 files changed, 292 insertions(+) create mode 100644 src/rgw/rgw_rest_account.cc create mode 100644 src/rgw/rgw_rest_account.h diff --git a/src/rgw/CMakeLists.txt b/src/rgw/CMakeLists.txt index 3de10300444..64b56492bfa 100644 --- a/src/rgw/CMakeLists.txt +++ b/src/rgw/CMakeLists.txt @@ -104,6 +104,7 @@ set(librgw_common_srcs rgw_quota.cc rgw_resolve.cc rgw_rest.cc + rgw_rest_account.cc rgw_rest_client.cc rgw_rest_config.cc rgw_rest_conn.cc diff --git a/src/rgw/rgw_appmain.cc b/src/rgw/rgw_appmain.cc index b4aa1019a73..b3e1765afc0 100644 --- a/src/rgw/rgw_appmain.cc +++ b/src/rgw/rgw_appmain.cc @@ -37,6 +37,7 @@ #include "rgw_rest_admin.h" #include "rgw_rest_info.h" #include "rgw_rest_usage.h" +#include "rgw_rest_account.h" #include "rgw_rest_bucket.h" #include "rgw_rest_metadata.h" #include "rgw_rest_log.h" @@ -360,6 +361,7 @@ void rgw::AppMain::cond_init_apis() RGWRESTMgr_Admin *admin_resource = new RGWRESTMgr_Admin; admin_resource->register_resource("info", new RGWRESTMgr_Info); admin_resource->register_resource("usage", new RGWRESTMgr_Usage); + admin_resource->register_resource("account", new RGWRESTMgr_Account); /* Register driver-specific admin APIs */ env.driver->register_admin_apis(admin_resource); rest.register_resource(g_conf()->rgw_admin_entry, admin_resource); diff --git a/src/rgw/rgw_common.cc b/src/rgw/rgw_common.cc index e93efa12f89..afd2f6dd352 100644 --- a/src/rgw/rgw_common.cc +++ b/src/rgw/rgw_common.cc @@ -133,6 +133,7 @@ rgw_http_errors rgw_http_s3_errors({ { ERR_NO_SUCH_TAG_SET, {404, "NoSuchTagSet"}}, { ERR_NO_SUCH_BUCKET_ENCRYPTION_CONFIGURATION, {404, "ServerSideEncryptionConfigurationNotFoundError"}}, { ERR_NO_SUCH_PUBLIC_ACCESS_BLOCK_CONFIGURATION, {404, "NoSuchPublicAccessBlockConfiguration"}}, + { ERR_ACCOUNT_EXISTS, {409, "AccountAlreadyExists"}}, }); rgw_http_errors rgw_http_swift_errors({ diff --git a/src/rgw/rgw_common.h b/src/rgw/rgw_common.h index 8f023d1225e..61b1d19a9b2 100644 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@ -322,6 +322,7 @@ static inline const char* to_mime_type(const RGWFormat f) #define ERR_INVALID_IDENTITY_TOKEN 2401 #define ERR_NO_SUCH_TAG_SET 2402 +#define ERR_ACCOUNT_EXISTS 2403 #ifndef UINT32_MAX #define UINT32_MAX (0xffffffffu) diff --git a/src/rgw/rgw_rest_account.cc b/src/rgw/rgw_rest_account.cc new file mode 100644 index 00000000000..1e1d367c4a7 --- /dev/null +++ b/src/rgw/rgw_rest_account.cc @@ -0,0 +1,241 @@ +// -*- 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 (C) 2020 SUSE LLC + * + * 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 "rgw_rest_account.h" +#include "rgw_account.h" +#include "rgw_process_env.h" + +class RGWOp_Account_Create : public RGWRESTOp { +public: + int check_caps(const RGWUserCaps& caps) override { + return caps.check_cap("accounts", RGW_CAP_WRITE); + } + + void execute(optional_yield y) override; + + const char* name() const override { return "create_account"; } +}; + +void RGWOp_Account_Create::execute(optional_yield y) +{ + rgw::account::AdminOpState op_state; + RESTArgs::get_string(s, "id", "", &op_state.account_id); + RESTArgs::get_string(s, "tenant", "", &op_state.tenant); + RESTArgs::get_string(s, "name", "", &op_state.account_name); + RESTArgs::get_string(s, "email", "", &op_state.email); + + uint32_t max_users = 0; + bool has_max_users = false; + RESTArgs::get_uint32(s, "max-users", 0, &max_users, &has_max_users); + if (has_max_users) { + op_state.max_users = max_users; + } + + uint32_t max_roles = 0; + bool has_max_roles = false; + RESTArgs::get_uint32(s, "max-roles", 0, &max_roles, &has_max_roles); + if (has_max_roles) { + op_state.max_roles = max_roles; + } + + uint32_t max_groups = 0; + bool has_max_groups = false; + RESTArgs::get_uint32(s, "max-groups", 0, &max_groups, &has_max_groups); + if (has_max_groups) { + op_state.max_groups = max_groups; + } + + uint32_t max_access_keys = 0; + bool has_max_access_keys = false; + RESTArgs::get_uint32(s, "max-access-keys", 0, &max_access_keys, &has_max_access_keys); + if (has_max_access_keys) { + op_state.max_access_keys = max_access_keys; + } + + uint32_t max_buckets = 0; + bool has_max_buckets = false; + RESTArgs::get_uint32(s, "max-buckets", 0, &max_buckets, &has_max_buckets); + if (has_max_buckets) { + op_state.max_buckets = max_buckets; + } + + if (!driver->is_meta_master()) { + bufferlist data; + JSONParser parser; + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + &data, &parser, s->info, y); + if (op_ret < 0) { + ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; + return; + } + + // the master zone may have generated its own account id, use the same + std::string meta_master_id; + JSONDecoder::decode_json("id", meta_master_id, &parser); + if (meta_master_id.empty()) { + ldpp_dout(this, 4) << "forward_request_to_master returned empty account id" << dendl; + op_ret = -EINVAL; + return; + } + op_state.account_id = meta_master_id; + } + + op_ret = rgw::account::create(this, driver, op_state, + s->err.message, flusher, y); + if (op_ret < 0) { + if (op_ret == -EEXIST) { + op_ret = -ERR_ACCOUNT_EXISTS; + } + } +} + +class RGWOp_Account_Modify : public RGWRESTOp { +public: + int check_caps(const RGWUserCaps& caps) override { + return caps.check_cap("accounts", RGW_CAP_WRITE); + } + + void execute(optional_yield y) override; + + const char* name() const override { return "modify_account"; } +}; + +void RGWOp_Account_Modify::execute(optional_yield y) +{ + bufferlist data; + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + &data, nullptr, s->info, y); + if (op_ret < 0) { + ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; + return; + } + + rgw::account::AdminOpState op_state; + RESTArgs::get_string(s, "id", "", &op_state.account_id); + RESTArgs::get_string(s, "tenant", "", &op_state.tenant); + RESTArgs::get_string(s, "name", "", &op_state.account_name); + RESTArgs::get_string(s, "email", "", &op_state.email); + + uint32_t max_users = 0; + bool has_max_users = false; + RESTArgs::get_uint32(s, "max-users", 0, &max_users, &has_max_users); + if (has_max_users) { + op_state.max_users = max_users; + } + + uint32_t max_roles = 0; + bool has_max_roles = false; + RESTArgs::get_uint32(s, "max-roles", 0, &max_roles, &has_max_roles); + if (has_max_roles) { + op_state.max_roles = max_roles; + } + + uint32_t max_groups = 0; + bool has_max_groups = false; + RESTArgs::get_uint32(s, "max-groups", 0, &max_groups, &has_max_groups); + if (has_max_groups) { + op_state.max_groups = max_groups; + } + + uint32_t max_access_keys = 0; + bool has_max_access_keys = false; + RESTArgs::get_uint32(s, "max-access-keys", 0, &max_access_keys, &has_max_access_keys); + if (has_max_access_keys) { + op_state.max_access_keys = max_access_keys; + } + + uint32_t max_buckets = 0; + bool has_max_buckets = false; + RESTArgs::get_uint32(s, "max-buckets", 0, &max_buckets, &has_max_buckets); + if (has_max_buckets) { + op_state.max_buckets = max_buckets; + } + + op_ret = rgw::account::modify(this, driver, op_state, + s->err.message, flusher, y); +} + + +class RGWOp_Account_Get : public RGWRESTOp { +public: + int check_caps(const RGWUserCaps& caps) override { + return caps.check_cap("account", RGW_CAP_READ); + } + + void execute(optional_yield y) override; + + const char* name() const override { return "get_account"; } +}; + +void RGWOp_Account_Get::execute(optional_yield y) +{ + rgw::account::AdminOpState op_state; + RESTArgs::get_string(s, "id", "", &op_state.account_id); + RESTArgs::get_string(s, "tenant", "", &op_state.tenant); + RESTArgs::get_string(s, "name", "", &op_state.account_name); + + op_ret = rgw::account::info(this, driver, op_state, + s->err.message, flusher, y); +} + +class RGWOp_Account_Delete : public RGWRESTOp { +public: + int check_caps(const RGWUserCaps& caps) override { + return caps.check_cap("account", RGW_CAP_WRITE); + } + + void execute(optional_yield y) override; + + const char* name() const override { return "delete_account"; } +}; + +void RGWOp_Account_Delete::execute(optional_yield y) +{ + bufferlist data; + op_ret = rgw_forward_request_to_master(this, *s->penv.site, s->user->get_id(), + &data, nullptr, s->info, y); + if (op_ret < 0) { + ldpp_dout(this, 0) << "forward_request_to_master returned ret=" << op_ret << dendl; + return; + } + + rgw::account::AdminOpState op_state; + RESTArgs::get_string(s, "id", "", &op_state.account_id); + RESTArgs::get_string(s, "tenant", "", &op_state.tenant); + RESTArgs::get_string(s, "name", "", &op_state.account_name); + + op_ret = rgw::account::remove(this, driver, op_state, + s->err.message, flusher, y); +} + +RGWOp* RGWHandler_Account::op_post() +{ + return new RGWOp_Account_Create; +} + +RGWOp* RGWHandler_Account::op_put() +{ + return new RGWOp_Account_Modify; +} + +RGWOp* RGWHandler_Account::op_get() +{ + return new RGWOp_Account_Get; +} + +RGWOp* RGWHandler_Account::op_delete() +{ + return new RGWOp_Account_Delete; +} diff --git a/src/rgw/rgw_rest_account.h b/src/rgw/rgw_rest_account.h new file mode 100644 index 00000000000..2df07a0efc3 --- /dev/null +++ b/src/rgw/rgw_rest_account.h @@ -0,0 +1,46 @@ +// -*- 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 (C) 2020 SUSE LLC + * + * 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 "rgw_rest.h" +#include "rgw_rest_s3.h" + +class RGWHandler_Account : public RGWHandler_Auth_S3 { + protected: + RGWOp *op_get() override; + RGWOp *op_put() override; + RGWOp *op_post() override; + RGWOp *op_delete() override; + public: + using RGWHandler_Auth_S3::RGWHandler_Auth_S3; + ~RGWHandler_Account() override = default; + + int read_permissions(RGWOp*, optional_yield y) override { + return 0; + } +}; + +class RGWRESTMgr_Account : public RGWRESTMgr { + public: + RGWRESTMgr_Account() = default; + ~RGWRESTMgr_Account() override = default; + + RGWHandler_REST *get_handler(rgw::sal::Driver* driver, struct req_state*, + const rgw::auth::StrategyRegistry& auth_registry, + const std::string&) override { + return new RGWHandler_Account(auth_registry); + } +}; -- 2.39.5