ldpp_dout(this, 1) << "successfully removed topic '" << topic_name << "'" << dendl;
}
-namespace {
-// utility classes and functions for handling parameters with the following format:
-// Attributes.entry.{N}.{key|value}={VALUE}
-// N - any unsigned number
-// VALUE - url encoded string
-
-// and Attribute is holding key and value
-// ctor and set are done according to the "type" argument
-// if type is not "key" or "value" its a no-op
-class Attribute {
- std::string key;
- std::string value;
-public:
- Attribute(const std::string& type, const std::string& key_or_value) {
- set(type, key_or_value);
- }
- void set(const std::string& type, const std::string& key_or_value) {
- if (type == "key") {
- key = key_or_value;
- } else if (type == "value") {
- value = key_or_value;
- }
- }
- const std::string& get_key() const { return key; }
- const std::string& get_value() const { return value; }
+using op_generator = RGWOp*(*)();
+static const std::unordered_map<std::string, op_generator> op_generators = {
+ {"CreateTopic", []() -> RGWOp* {return new RGWPSCreateTopicOp;}},
+ {"DeleteTopic", []() -> RGWOp* {return new RGWPSDeleteTopicOp;}},
+ {"ListTopics", []() -> RGWOp* {return new RGWPSListTopicsOp;}},
+ {"GetTopic", []() -> RGWOp* {return new RGWPSGetTopicOp;}},
+ {"GetTopicAttributes", []() -> RGWOp* {return new RGWPSGetTopicAttributesOp;}}
};
-using AttributeMap = std::map<unsigned, Attribute>;
-
-// aggregate the attributes into a map
-// the key and value are associated by the index (N)
-// no assumptions are made on the order in which these parameters are added
-void update_attribute_map(const std::string& input, AttributeMap& map) {
- const boost::char_separator<char> sep(".");
- const boost::tokenizer tokens(input, sep);
- auto token = tokens.begin();
- if (*token != "Attributes") {
- return;
- }
- ++token;
-
- if (*token != "entry") {
- return;
- }
- ++token;
-
- unsigned idx;
- try {
- idx = std::stoul(*token);
- } catch (const std::invalid_argument&) {
- return;
- }
- ++token;
-
- std::string key_or_value = "";
- // get the rest of the string regardless of dots
- // this is to allow dots in the value
- while (token != tokens.end()) {
- key_or_value.append(*token+".");
- ++token;
- }
- // remove last separator
- key_or_value.pop_back();
-
- auto pos = key_or_value.find("=");
- if (pos != std::string::npos) {
- const auto key_or_value_lhs = key_or_value.substr(0, pos);
- const auto key_or_value_rhs = url_decode(key_or_value.substr(pos + 1, key_or_value.size() - 1));
- const auto map_it = map.find(idx);
- if (map_it == map.end()) {
- // new entry
- map.emplace(std::make_pair(idx, Attribute(key_or_value_lhs, key_or_value_rhs)));
- } else {
- // existing entry
- map_it->second.set(key_or_value_lhs, key_or_value_rhs);
- }
- }
-}
-}
-
-void RGWHandler_REST_PSTopic_AWS::rgw_topic_parse_input() {
- if (post_body.size() > 0) {
- ldpp_dout(s, 10) << "Content of POST: " << post_body << dendl;
-
- if (post_body.find("Action") != std::string::npos) {
- const boost::char_separator<char> sep("&");
- const boost::tokenizer<boost::char_separator<char>> tokens(post_body, sep);
- AttributeMap map;
- for (const auto& t : tokens) {
- auto pos = t.find("=");
- if (pos != std::string::npos) {
- const auto key = t.substr(0, pos);
- if (key == "Action") {
- s->info.args.append(key, t.substr(pos + 1, t.size() - 1));
- } else if (key == "Name" || key == "TopicArn") {
- const auto value = url_decode(t.substr(pos + 1, t.size() - 1));
- s->info.args.append(key, value);
- } else {
- update_attribute_map(t, map);
- }
- }
- }
- // update the regular args with the content of the attribute map
- for (const auto& attr : map) {
- s->info.args.append(attr.second.get_key(), attr.second.get_value());
- }
- }
- const auto payload_hash = rgw::auth::s3::calc_v4_payload_hash(post_body);
- s->info.args.append("PayloadHash", payload_hash);
+bool RGWHandler_REST_PSTopic_AWS::action_exists(const req_state* s)
+{
+ if (s->info.args.exists("Action")) {
+ const std::string action_name = s->info.args.get("Action");
+ return op_generators.contains(action_name);
}
+ return false;
}
-RGWOp* RGWHandler_REST_PSTopic_AWS::op_post() {
- rgw_topic_parse_input();
+RGWOp *RGWHandler_REST_PSTopic_AWS::op_post()
+{
+ s->dialect = "sns";
+ s->prot_flags = RGW_REST_STS;
if (s->info.args.exists("Action")) {
- const auto action = s->info.args.get("Action");
- if (action.compare("CreateTopic") == 0)
- return new RGWPSCreateTopicOp();
- if (action.compare("DeleteTopic") == 0)
- return new RGWPSDeleteTopicOp;
- if (action.compare("ListTopics") == 0)
- return new RGWPSListTopicsOp();
- if (action.compare("GetTopic") == 0)
- return new RGWPSGetTopicOp();
- if (action.compare("GetTopicAttributes") == 0)
- return new RGWPSGetTopicAttributesOp();
+ const std::string action_name = s->info.args.get("Action");
+ const auto action_it = op_generators.find(action_name);
+ if (action_it != op_generators.end()) {
+ return action_it->second();
+ }
+ ldpp_dout(s, 10) << "unknown action '" << action_name << "' for Topic handler" << dendl;
+ } else {
+ ldpp_dout(s, 10) << "missing action argument in Topic handler" << dendl;
}
-
return nullptr;
}
// AWS compliant topics handler factory
class RGWHandler_REST_PSTopic_AWS : public RGWHandler_REST {
const rgw::auth::StrategyRegistry& auth_registry;
- const std::string& post_body;
- void rgw_topic_parse_input();
protected:
RGWOp* op_post() override;
public:
- RGWHandler_REST_PSTopic_AWS(const rgw::auth::StrategyRegistry& _auth_registry, const std::string& _post_body) :
- auth_registry(_auth_registry),
- post_body(_post_body) {}
+ RGWHandler_REST_PSTopic_AWS(const rgw::auth::StrategyRegistry& _auth_registry) :
+ auth_registry(_auth_registry) {}
virtual ~RGWHandler_REST_PSTopic_AWS() = default;
int postauth_init(optional_yield) override { return 0; }
int authorize(const DoutPrefixProvider* dpp, optional_yield y) override;
+ static bool action_exists(const req_state* s);
};
+
const vector<rgw::IAM::Policy>& user_policies,
const vector<rgw::IAM::Policy>& session_policies,
const rgw::ARN& res,
- const uint64_t op)
+ const uint64_t op,
+ bool mandatory_policy)
{
auto identity_policy_res = eval_identity_or_session_policies(dpp, user_policies, s->env, op, res);
if (identity_policy_res == Effect::Deny) {
return true;
}
- if (op == rgw::IAM::s3CreateBucket || op == rgw::IAM::s3ListAllMyBuckets) {
- auto perm = op_to_perm(op);
-
- return verify_user_permission_no_policy(dpp, s, user_acl, perm);
+ if (mandatory_policy) {
+ // no policies, and policy is mandatory
+ ldpp_dout(dpp, 20) << "no policies for a policy mandatory op " << op << dendl;
+ return false;
}
- return false;
+ auto perm = op_to_perm(op);
+
+ return verify_user_permission_no_policy(dpp, s, user_acl, perm);
}
bool verify_user_permission_no_policy(const DoutPrefixProvider* dpp,
bool verify_user_permission(const DoutPrefixProvider* dpp,
req_state * const s,
const rgw::ARN& res,
- const uint64_t op)
+ const uint64_t op,
+ bool mandatory_policy)
{
perm_state_from_req_state ps(s);
- return verify_user_permission(dpp, &ps, s->user_acl.get(), s->iam_user_policies, s->session_policies, res, op);
+ return verify_user_permission(dpp, &ps, s->user_acl.get(), s->iam_user_policies, s->session_policies, res, op, mandatory_policy);
}
bool verify_user_permission_no_policy(const DoutPrefixProvider* dpp,
#define RGW_REST_WEBSITE 0x8
#define RGW_REST_STS 0x10
#define RGW_REST_IAM 0x20
+#define RGW_REST_SNS 0x30
#define RGW_SUSPENDED_USER_AUID (uint64_t)-2
const std::vector<rgw::IAM::Policy>& user_policies,
const std::vector<rgw::IAM::Policy>& session_policies,
const rgw::ARN& res,
- const uint64_t op);
+ const uint64_t op,
+ bool mandatory_policy=true);
bool verify_user_permission_no_policy(const DoutPrefixProvider* dpp,
req_state * const s,
RGWAccessControlPolicy * const user_acl,
bool verify_user_permission(const DoutPrefixProvider* dpp,
req_state * const s,
const rgw::ARN& res,
- const uint64_t op);
+ const uint64_t op,
+ bool mandatory_policy=true);
bool verify_user_permission_no_policy(const DoutPrefixProvider* dpp,
req_state * const s,
int perm);
tenant = s->user->get_tenant();
}
- if (!verify_user_permission(this, s, ARN(partition, service, "", tenant, "*"), rgw::IAM::s3ListAllMyBuckets)) {
+ if (!verify_user_permission(this, s, ARN(partition, service, "", tenant, "*"), rgw::IAM::s3ListAllMyBuckets, false)) {
return -EACCES;
}
bucket.name = s->bucket_name;
bucket.tenant = s->bucket_tenant;
ARN arn = ARN(bucket);
- if (!verify_user_permission(this, s, arn, rgw::IAM::s3CreateBucket)) {
+ if (!verify_user_permission(this, s, arn, rgw::IAM::s3CreateBucket, false)) {
return -EACCES;
}
RGWQuota quota;
int op_ret;
int do_aws4_auth_completion();
+ bool init_called = false;
virtual int init_quota();
}
virtual void init(rgw::sal::Driver* driver, req_state *s, RGWHandler *dialect_handler) {
+ if (init_called) return;
this->driver = driver;
+ init_called = true;
this->s = s;
this->dialect_handler = dialect_handler;
}
*init_error = -ERR_METHOD_NOT_ALLOWED;
return NULL;
}
+
+ ldpp_dout(s, 20) << __func__ << " handler=" << typeid(*handler).name() << dendl;
+
*init_error = handler->init(driver, s, rio);
if (*init_error < 0) {
m->put_handler(handler);
using namespace std;
-void RGWHandler_REST_IAM::rgw_iam_parse_input()
+using op_generator = RGWOp*(*)(const bufferlist&);
+static const std::unordered_map<std::string_view, op_generator> op_generators = {
+ {"CreateRole", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWCreateRole(bl_post_body);}},
+ {"DeleteRole", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWDeleteRole(bl_post_body);}},
+ {"GetRole", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWGetRole;}},
+ {"UpdateAssumeRolePolicy", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWModifyRoleTrustPolicy(bl_post_body);}},
+ {"ListRoles", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWListRoles;}},
+ {"PutRolePolicy", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWPutRolePolicy(bl_post_body);}},
+ {"GetRolePolicy", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWGetRolePolicy;}},
+ {"ListRolePolicies", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWListRolePolicies;}},
+ {"DeleteRolePolicy", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWDeleteRolePolicy(bl_post_body);}},
+ {"PutUserPolicy", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWPutUserPolicy;}},
+ {"GetUserPolicy", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWGetUserPolicy;}},
+ {"ListUserPolicies", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWListUserPolicies;}},
+ {"DeleteUserPolicy", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWDeleteUserPolicy;}},
+ {"CreateOpenIDConnectProvider", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWCreateOIDCProvider;}},
+ {"ListOpenIDConnectProviders", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWListOIDCProviders;}},
+ {"GetOpenIDConnectProvider", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWGetOIDCProvider;}},
+ {"DeleteOpenIDConnectProvider", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWDeleteOIDCProvider;}},
+ {"TagRole", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWTagRole(bl_post_body);}},
+ {"ListRoleTags", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWListRoleTags;}},
+ {"UntagRole", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWUntagRole(bl_post_body);}},
+ {"UpdateRole", [](const bufferlist& bl_post_body) -> RGWOp* {return new RGWUpdateRole(bl_post_body);}}
+};
+
+bool RGWHandler_REST_IAM::action_exists(const req_state* s)
{
- std::string post_body = bl_post_body.to_str();
- if (post_body.size() > 0) {
- ldpp_dout(s, 10) << "Content of POST: " << post_body << dendl;
-
- if (post_body.find("Action") != string::npos) {
- boost::char_separator<char> sep("&");
- boost::tokenizer<boost::char_separator<char>> tokens(post_body, sep);
- for (const auto& t : tokens) {
- auto pos = t.find("=");
- if (pos != string::npos) {
- s->info.args.append(t.substr(0,pos),
- url_decode(t.substr(pos+1, t.size() -1)));
- }
- }
- }
+ if (s->info.args.exists("Action")) {
+ const std::string action_name = s->info.args.get("Action");
+ return op_generators.contains(action_name);
}
- auto payload_hash = rgw::auth::s3::calc_v4_payload_hash(post_body);
- s->info.args.append("PayloadHash", payload_hash);
+ return false;
}
RGWOp *RGWHandler_REST_IAM::op_post()
{
- rgw_iam_parse_input();
-
if (s->info.args.exists("Action")) {
- string action = s->info.args.get("Action");
- if (action.compare("CreateRole") == 0)
- return new RGWCreateRole(this->bl_post_body);
- if (action.compare("DeleteRole") == 0)
- return new RGWDeleteRole(this->bl_post_body);
- if (action.compare("GetRole") == 0)
- return new RGWGetRole;
- if (action.compare("UpdateAssumeRolePolicy") == 0)
- return new RGWModifyRoleTrustPolicy(this->bl_post_body);
- if (action.compare("ListRoles") == 0)
- return new RGWListRoles;
- if (action.compare("PutRolePolicy") == 0)
- return new RGWPutRolePolicy(this->bl_post_body);
- if (action.compare("GetRolePolicy") == 0)
- return new RGWGetRolePolicy;
- if (action.compare("ListRolePolicies") == 0)
- return new RGWListRolePolicies;
- if (action.compare("DeleteRolePolicy") == 0)
- return new RGWDeleteRolePolicy(this->bl_post_body);
- if (action.compare("PutUserPolicy") == 0)
- return new RGWPutUserPolicy;
- if (action.compare("GetUserPolicy") == 0)
- return new RGWGetUserPolicy;
- if (action.compare("ListUserPolicies") == 0)
- return new RGWListUserPolicies;
- if (action.compare("DeleteUserPolicy") == 0)
- return new RGWDeleteUserPolicy;
- if (action.compare("CreateOpenIDConnectProvider") == 0)
- return new RGWCreateOIDCProvider;
- if (action.compare("ListOpenIDConnectProviders") == 0)
- return new RGWListOIDCProviders;
- if (action.compare("GetOpenIDConnectProvider") == 0)
- return new RGWGetOIDCProvider;
- if (action.compare("DeleteOpenIDConnectProvider") == 0)
- return new RGWDeleteOIDCProvider;
- if (action.compare("TagRole") == 0)
- return new RGWTagRole(this->bl_post_body);
- if (action.compare("ListRoleTags") == 0)
- return new RGWListRoleTags;
- if (action.compare("UntagRole") == 0)
- return new RGWUntagRole(this->bl_post_body);
- if (action.compare("UpdateRole") == 0)
- return new RGWUpdateRole(this->bl_post_body);
+ const std::string action_name = s->info.args.get("Action");
+ const auto action_it = op_generators.find(action_name);
+ if (action_it != op_generators.end()) {
+ return action_it->second(bl_post_body);
+ }
+ ldpp_dout(s, 10) << "unknown action '" << action_name << "' for IAM handler" << dendl;
+ } else {
+ ldpp_dout(s, 10) << "missing action argument in IAM handler" << dendl;
}
-
return nullptr;
}
rgw::io::BasicClient *cio)
{
s->dialect = "iam";
-
- if (int ret = RGWHandler_REST_IAM::init_from_header(s, RGWFormat::XML, true); ret < 0) {
- ldpp_dout(s, 10) << "init_from_header returned err=" << ret << dendl;
- return ret;
- }
+ s->prot_flags = RGW_REST_IAM;
return RGWHandler_REST::init(driver, s, cio);
}
return RGW_Auth_S3::authorize(dpp, driver, auth_registry, s, y);
}
-int RGWHandler_REST_IAM::init_from_header(req_state* s,
- RGWFormat default_formatter,
- bool configurable_format)
-{
- string req;
- string first;
-
- s->prot_flags = RGW_REST_IAM;
-
- const char *p, *req_name;
- if (req_name = s->relative_uri.c_str(); *req_name == '?') {
- p = req_name;
- } else {
- p = s->info.request_params.c_str();
- }
-
- s->info.args.set(p);
- s->info.args.parse(s);
-
- /* must be called after the args parsing */
- if (int ret = allocate_formatter(s, default_formatter, configurable_format); ret < 0)
- return ret;
-
- if (*req_name != '/')
- return 0;
-
- req_name++;
-
- if (!*req_name)
- return 0;
-
- req = req_name;
- int pos = req.find('/');
- if (pos >= 0) {
- first = req.substr(0, pos);
- } else {
- first = req;
- }
-
- return 0;
-}
-
RGWHandler_REST*
RGWRESTMgr_IAM::get_handler(rgw::sal::Driver* driver,
req_state* const s,
const rgw::auth::StrategyRegistry& auth_registry;
bufferlist bl_post_body;
RGWOp *op_post() override;
- void rgw_iam_parse_input();
+
public:
- static int init_from_header(req_state *s, RGWFormat default_formatter, bool configurable_format);
+ static bool action_exists(const req_state* s);
RGWHandler_REST_IAM(const rgw::auth::StrategyRegistry& auth_registry,
bufferlist& bl_post_body)
#include "auth/Crypto.h"
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/replace.hpp>
+#include <boost/algorithm/string/predicate.hpp>
#include <boost/tokenizer.hpp>
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
#ifdef HAVE_WARN_IMPLICIT_CONST_INT_FLOAT_CONVERSION
return new RGWListBuckets_ObjStore_S3;
}
-RGWOp *RGWHandler_REST_Service_S3::op_post()
-{
- const auto max_size = s->cct->_conf->rgw_max_put_param_size;
-
- int ret;
- bufferlist data;
- std::tie(ret, data) = rgw_rest_read_all_input(s, max_size, false);
- if (ret < 0) {
- return nullptr;
- }
-
- const auto post_body = data.to_str();
-
- if (isSTSEnabled) {
- RGWHandler_REST_STS sts_handler(auth_registry, post_body);
- sts_handler.init(driver, s, s->cio);
- auto op = sts_handler.get_op();
- if (op) {
- return op;
- }
- }
-
- if (isIAMEnabled) {
- RGWHandler_REST_IAM iam_handler(auth_registry, data);
- iam_handler.init(driver, s, s->cio);
- auto op = iam_handler.get_op();
- if (op) {
- return op;
- }
- }
-
- if (isPSEnabled) {
- RGWHandler_REST_PSTopic_AWS topic_handler(auth_registry, post_body);
- topic_handler.init(driver, s, s->cio);
- auto op = topic_handler.get_op();
- if (op) {
- return op;
- }
- }
-
- return nullptr;
-}
-
RGWOp *RGWHandler_REST_Bucket_S3::get_obj_op(bool get_data) const
{
// Non-website mode
return RGWHandler_REST::init(driver, state, cio);
}
+namespace {
+// utility classes and functions for handling parameters with the following format:
+// Attributes.entry.{N}.{key|value}={VALUE}
+// N - any unsigned number
+// VALUE - url encoded string
+
+// and Attribute is holding key and value
+// ctor and set are done according to the "type" argument
+// if type is not "key" or "value" its a no-op
+class Attribute {
+ std::string key;
+ std::string value;
+public:
+ Attribute(const std::string& type, const std::string& key_or_value) {
+ set(type, key_or_value);
+ }
+ void set(const std::string& type, const std::string& key_or_value) {
+ if (type == "key") {
+ key = key_or_value;
+ } else if (type == "value") {
+ value = key_or_value;
+ }
+ }
+ const std::string& get_key() const { return key; }
+ const std::string& get_value() const { return value; }
+};
+
+using AttributeMap = std::map<unsigned, Attribute>;
+
+// aggregate the attributes into a map
+// the key and value are associated by the index (N)
+// no assumptions are made on the order in which these parameters are added
+void update_attribute_map(const std::string& input, AttributeMap& map) {
+ const boost::char_separator<char> sep(".");
+ const boost::tokenizer tokens(input, sep);
+ auto token = tokens.begin();
+ if (*token != "Attributes") {
+ return;
+ }
+ ++token;
+
+ if (*token != "entry") {
+ return;
+ }
+ ++token;
+
+ unsigned idx;
+ try {
+ idx = std::stoul(*token);
+ } catch (const std::invalid_argument&) {
+ return;
+ }
+ ++token;
+
+ std::string key_or_value = "";
+ // get the rest of the string regardless of dots
+ // this is to allow dots in the value
+ while (token != tokens.end()) {
+ key_or_value.append(*token+".");
+ ++token;
+ }
+ // remove last separator
+ key_or_value.pop_back();
+
+ auto pos = key_or_value.find("=");
+ if (pos != std::string::npos) {
+ const auto key_or_value_lhs = key_or_value.substr(0, pos);
+ const auto key_or_value_rhs = url_decode(key_or_value.substr(pos + 1, key_or_value.size() - 1));
+ const auto map_it = map.find(idx);
+ if (map_it == map.end()) {
+ // new entry
+ map.emplace(std::make_pair(idx, Attribute(key_or_value_lhs, key_or_value_rhs)));
+ } else {
+ // existing entry
+ map_it->second.set(key_or_value_lhs, key_or_value_rhs);
+ }
+ }
+}
+}
+
+void parse_post_action(const std::string& post_body, req_state* s)
+{
+ if (post_body.size() > 0) {
+ ldpp_dout(s, 10) << "Content of POST: " << post_body << dendl;
+
+ if (post_body.find("Action") != string::npos) {
+ const boost::char_separator<char> sep("&");
+ const boost::tokenizer<boost::char_separator<char>> tokens(post_body, sep);
+ AttributeMap map;
+ for (const auto& t : tokens) {
+ const auto pos = t.find("=");
+ if (pos != string::npos) {
+ const auto key = t.substr(0, pos);
+ if (boost::starts_with(key, "Attributes.")) {
+ update_attribute_map(t, map);
+ } else {
+ s->info.args.append(t.substr(0, pos),
+ url_decode(t.substr(pos+1, t.size() -1)));
+ }
+ }
+ }
+ // update the regular args with the content of the attribute map
+ for (const auto& attr : map) {
+ s->info.args.append(attr.second.get_key(), attr.second.get_value());
+ }
+ }
+ }
+ const auto payload_hash = rgw::auth::s3::calc_v4_payload_hash(post_body);
+ s->info.args.append("PayloadHash", payload_hash);
+}
+
RGWHandler_REST* RGWRESTMgr_S3::get_handler(rgw::sal::Driver* driver,
req_state* const s,
const rgw::auth::StrategyRegistry& auth_registry,
RGWHandler_REST_S3::init_from_header(driver, s,
is_s3website ? RGWFormat::HTML :
RGWFormat::XML, true);
- if (ret < 0)
- return NULL;
+ if (ret < 0) {
+ return nullptr;
+ }
- RGWHandler_REST* handler;
- // TODO: Make this more readable
if (is_s3website) {
if (s->init_state.url_bucket.empty()) {
- handler = new RGWHandler_REST_Service_S3Website(auth_registry);
- } else if (rgw::sal::Object::empty(s->object.get())) {
- handler = new RGWHandler_REST_Bucket_S3Website(auth_registry);
- } else {
- handler = new RGWHandler_REST_Obj_S3Website(auth_registry);
+ return new RGWHandler_REST_Service_S3Website(auth_registry);
}
- } else {
- if (s->init_state.url_bucket.empty()) {
- handler = new RGWHandler_REST_Service_S3(auth_registry, enable_sts, enable_iam, enable_pubsub);
- } else if (!rgw::sal::Object::empty(s->object.get())) {
- handler = new RGWHandler_REST_Obj_S3(auth_registry);
- } else if (s->info.args.exist_obj_excl_sub_resource()) {
- return NULL;
- } else {
- handler = new RGWHandler_REST_Bucket_S3(auth_registry, enable_pubsub);
+ if (rgw::sal::Object::empty(s->object.get())) {
+ return new RGWHandler_REST_Bucket_S3Website(auth_registry);
}
+ return new RGWHandler_REST_Obj_S3Website(auth_registry);
}
- ldpp_dout(s, 20) << __func__ << " handler=" << typeid(*handler).name()
- << dendl;
- return handler;
+ if (s->init_state.url_bucket.empty()) {
+ // no bucket
+ if (s->op == OP_POST) {
+ // POST will be one of: IAM, STS or topic service
+ const auto max_size = s->cct->_conf->rgw_max_put_param_size;
+ int ret;
+ bufferlist data;
+ std::tie(ret, data) = rgw_rest_read_all_input(s, max_size, false);
+ if (ret < 0) {
+ return nullptr;
+ }
+ parse_post_action(data.to_str(), s);
+ if (enable_sts && RGWHandler_REST_STS::action_exists(s)) {
+ return new RGWHandler_REST_STS(auth_registry);
+ }
+ if (enable_iam && RGWHandler_REST_IAM::action_exists(s)) {
+ return new RGWHandler_REST_IAM(auth_registry, data);
+ }
+ if (enable_pubsub && RGWHandler_REST_PSTopic_AWS::action_exists(s)) {
+ return new RGWHandler_REST_PSTopic_AWS(auth_registry);
+ }
+ return nullptr;
+ }
+ // non-POST S3 service without a bucket
+ return new RGWHandler_REST_Service_S3(auth_registry);
+ }
+ if (!rgw::sal::Object::empty(s->object.get())) {
+ // has object
+ return new RGWHandler_REST_Obj_S3(auth_registry);
+ }
+ if (s->info.args.exist_obj_excl_sub_resource()) {
+ return nullptr;
+ }
+ // has bucket
+ return new RGWHandler_REST_Bucket_S3(auth_registry, enable_pubsub);
}
bool RGWHandler_REST_S3Website::web_dir() const {
class RGWHandler_REST_Service_S3 : public RGWHandler_REST_S3 {
protected:
- const bool isSTSEnabled;
- const bool isIAMEnabled;
- const bool isPSEnabled;
bool is_usage_op() const {
return s->info.args.exists("usage");
}
RGWOp *op_get() override;
RGWOp *op_head() override;
- RGWOp *op_post() override;
public:
- RGWHandler_REST_Service_S3(const rgw::auth::StrategyRegistry& auth_registry,
- bool _isSTSEnabled, bool _isIAMEnabled, bool _isPSEnabled) :
- RGWHandler_REST_S3(auth_registry), isSTSEnabled(_isSTSEnabled), isIAMEnabled(_isIAMEnabled), isPSEnabled(_isPSEnabled) {}
+ RGWHandler_REST_Service_S3(const rgw::auth::StrategyRegistry& auth_registry) :
+ RGWHandler_REST_S3(auth_registry) {}
~RGWHandler_REST_Service_S3() override = default;
};
return rgw::auth::Strategy::apply(dpp, auth_registry.get_sts(), s, y);
}
-void RGWHandler_REST_STS::rgw_sts_parse_input()
+using op_generator = RGWOp*(*)();
+static const std::unordered_map<std::string_view, op_generator> op_generators = {
+ {"AssumeRole", []() -> RGWOp* {return new RGWSTSAssumeRole;}},
+ {"GetSessionToken", []() -> RGWOp* {return new RGWSTSGetSessionToken;}},
+ {"AssumeRoleWithWebIdentity", []() -> RGWOp* {return new RGWSTSAssumeRoleWithWebIdentity;}}
+};
+
+bool RGWHandler_REST_STS::action_exists(const req_state* s)
{
- if (post_body.size() > 0) {
- ldpp_dout(s, 10) << "Content of POST: " << post_body << dendl;
-
- if (post_body.find("Action") != string::npos) {
- boost::char_separator<char> sep("&");
- boost::tokenizer<boost::char_separator<char>> tokens(post_body, sep);
- for (const auto& t : tokens) {
- auto pos = t.find("=");
- if (pos != string::npos) {
- s->info.args.append(t.substr(0,pos),
- url_decode(t.substr(pos+1, t.size() -1)));
- }
- }
- }
+ if (s->info.args.exists("Action")) {
+ const std::string action_name = s->info.args.get("Action");
+ return op_generators.contains(action_name);
}
- auto payload_hash = rgw::auth::s3::calc_v4_payload_hash(post_body);
- s->info.args.append("PayloadHash", payload_hash);
+ return false;
}
RGWOp *RGWHandler_REST_STS::op_post()
{
- rgw_sts_parse_input();
-
- if (s->info.args.exists("Action")) {
- string action = s->info.args.get("Action");
- if (action == "AssumeRole") {
- return new RGWSTSAssumeRole;
- } else if (action == "GetSessionToken") {
- return new RGWSTSGetSessionToken;
- } else if (action == "AssumeRoleWithWebIdentity") {
- return new RGWSTSAssumeRoleWithWebIdentity;
+ if (s->info.args.exists("Action")) {
+ const std::string action_name = s->info.args.get("Action");
+ const auto action_it = op_generators.find(action_name);
+ if (action_it != op_generators.end()) {
+ return action_it->second();
}
+ ldpp_dout(s, 10) << "unknown action '" << action_name << "' for STS handler" << dendl;
+ } else {
+ ldpp_dout(s, 10) << "missing action argument in STS handler" << dendl;
}
-
return nullptr;
}
rgw::io::BasicClient *cio)
{
s->dialect = "sts";
-
- if (int ret = RGWHandler_REST_STS::init_from_header(s, RGWFormat::XML, true); ret < 0) {
- ldpp_dout(s, 10) << "init_from_header returned err=" << ret << dendl;
- return ret;
- }
+ s->prot_flags = RGW_REST_STS;
return RGWHandler_REST::init(driver, s, cio);
}
return RGW_Auth_S3::authorize(dpp, driver, auth_registry, s, y);
}
-int RGWHandler_REST_STS::init_from_header(req_state* s,
- RGWFormat default_formatter,
- bool configurable_format)
-{
- string req;
- string first;
-
- s->prot_flags = RGW_REST_STS;
-
- const char *p, *req_name;
- if (req_name = s->relative_uri.c_str(); *req_name == '?') {
- p = req_name;
- } else {
- p = s->info.request_params.c_str();
- }
-
- s->info.args.set(p);
- s->info.args.parse(s);
-
- /* must be called after the args parsing */
- if (int ret = allocate_formatter(s, default_formatter, configurable_format); ret < 0)
- return ret;
-
- if (*req_name != '/')
- return 0;
-
- req_name++;
-
- if (!*req_name)
- return 0;
-
- req = req_name;
- int pos = req.find('/');
- if (pos >= 0) {
- first = req.substr(0, pos);
- } else {
- first = req;
- }
-
- return 0;
-}
-
RGWHandler_REST*
RGWRESTMgr_STS::get_handler(rgw::sal::Driver* driver,
req_state* const s,
class RGWHandler_REST_STS : public RGWHandler_REST {
const rgw::auth::StrategyRegistry& auth_registry;
- const std::string& post_body;
RGWOp *op_post() override;
- void rgw_sts_parse_input();
public:
- static int init_from_header(req_state *s, RGWFormat default_formatter, bool configurable_format);
+ static bool action_exists(const req_state* s);
- RGWHandler_REST_STS(const rgw::auth::StrategyRegistry& auth_registry, const std::string& post_body="")
+ RGWHandler_REST_STS(const rgw::auth::StrategyRegistry& auth_registry)
: RGWHandler_REST(),
- auth_registry(auth_registry),
- post_body(post_body) {}
+ auth_registry(auth_registry) {}
~RGWHandler_REST_STS() override = default;
int init(rgw::sal::Driver* driver,