// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab ft=cpp #include #include #include "common/errno.h" #include "common/Formatter.h" #include "common/ceph_json.h" #include "include/types.h" #include "rgw_string.h" #include "rgw_common.h" #include "rgw_op.h" #include "rgw_rest.h" #include "rgw_rest_user_policy.h" #include "rgw_sal.h" #include "services/svc_zone.h" #define dout_subsys ceph_subsys_rgw void RGWRestUserPolicy::dump(Formatter *f) const { encode_json("PolicyName", policy_name , f); encode_json("UserName", user_name , f); encode_json("PolicyDocument", policy, f); } void RGWRestUserPolicy::send_response() { if (op_ret) { set_req_state_err(s, op_ret); } dump_errno(s); end_header(s); } int RGWRestUserPolicy::verify_permission(optional_yield y) { if (s->auth.identity->is_anonymous()) { return -EACCES; } if(int ret = check_caps(s->user->get_caps()); ret == 0) { return ret; } uint64_t op = get_op(); std::string user_name = s->info.args.get("UserName"); rgw_user user_id(user_name); if (! verify_user_permission(this, s, rgw::ARN(rgw::ARN(user_id.id, "user", user_id.tenant)), op)) { return -EACCES; } return 0; } bool RGWRestUserPolicy::validate_input() { if (policy_name.length() > MAX_POLICY_NAME_LEN) { ldpp_dout(this, 0) << "ERROR: Invalid policy name length " << dendl; return false; } std::regex regex_policy_name("[A-Za-z0-9:=,.@-]+"); if (! std::regex_match(policy_name, regex_policy_name)) { ldpp_dout(this, 0) << "ERROR: Invalid chars in policy name " << dendl; return false; } return true; } int RGWUserPolicyRead::check_caps(const RGWUserCaps& caps) { return caps.check_cap("user-policy", RGW_CAP_READ); } int RGWUserPolicyWrite::check_caps(const RGWUserCaps& caps) { return caps.check_cap("user-policy", RGW_CAP_WRITE); } uint64_t RGWPutUserPolicy::get_op() { return rgw::IAM::iamPutUserPolicy; } int RGWPutUserPolicy::get_params() { policy_name = url_decode(s->info.args.get("PolicyName"), true); user_name = url_decode(s->info.args.get("UserName"), true); policy = url_decode(s->info.args.get("PolicyDocument"), true); if (policy_name.empty() || user_name.empty() || policy.empty()) { ldpp_dout(this, 20) << "ERROR: one of policy name, user name or policy document is empty" << dendl; return -EINVAL; } if (! validate_input()) { return -EINVAL; } return 0; } void RGWPutUserPolicy::execute(optional_yield y) { op_ret = get_params(); if (op_ret < 0) { return; } bufferlist bl = bufferlist::static_from_string(policy); std::unique_ptr user = driver->get_user(rgw_user(user_name)); op_ret = user->load_user(s, s->yield); if (op_ret < 0) { op_ret = -ERR_NO_SUCH_ENTITY; return; } op_ret = user->read_attrs(s, s->yield); if (op_ret == -ENOENT) { op_ret = -ERR_NO_SUCH_ENTITY; return; } ceph::bufferlist in_data; op_ret = driver->forward_request_to_master(this, s->user.get(), nullptr, in_data, nullptr, s->info, y); if (op_ret < 0) { ldpp_dout(this, 0) << "ERROR: forward_request_to_master returned ret=" << op_ret << dendl; return; } try { const rgw::IAM::Policy p( s->cct, s->user->get_tenant(), bl, s->cct->_conf.get_val("rgw_policy_reject_invalid_principals")); std::map policies; if (auto it = user->get_attrs().find(RGW_ATTR_USER_POLICY); it != user->get_attrs().end()) { bufferlist out_bl = it->second; decode(policies, out_bl); } bufferlist in_bl; policies[policy_name] = policy; constexpr unsigned int USER_POLICIES_MAX_NUM = 100; const unsigned int max_num = s->cct->_conf->rgw_user_policies_max_num < 0 ? USER_POLICIES_MAX_NUM : s->cct->_conf->rgw_user_policies_max_num; if (policies.size() > max_num) { ldpp_dout(this, 4) << "IAM user policies has reached the num config: " << max_num << ", cant add another" << dendl; op_ret = -ERR_INVALID_REQUEST; s->err.message = "The number of IAM user policies should not exceed allowed limit " "of " + std::to_string(max_num) + " policies."; return; } encode(policies, in_bl); user->get_attrs()[RGW_ATTR_USER_POLICY] = in_bl; op_ret = user->store_user(s, s->yield, false); if (op_ret < 0) { op_ret = -ERR_INTERNAL_ERROR; } } catch (buffer::error& err) { ldpp_dout(this, 0) << "ERROR: failed to decode user policies" << dendl; op_ret = -EIO; } catch (rgw::IAM::PolicyParseException& e) { ldpp_dout(this, 5) << "failed to parse policy: " << e.what() << dendl; s->err.message = e.what(); op_ret = -ERR_MALFORMED_DOC; } if (op_ret == 0) { s->formatter->open_object_section("PutUserPolicyResponse"); s->formatter->open_object_section("ResponseMetadata"); s->formatter->dump_string("RequestId", s->trans_id); s->formatter->close_section(); s->formatter->close_section(); } } uint64_t RGWGetUserPolicy::get_op() { return rgw::IAM::iamGetUserPolicy; } int RGWGetUserPolicy::get_params() { policy_name = s->info.args.get("PolicyName"); user_name = s->info.args.get("UserName"); if (policy_name.empty() || user_name.empty()) { ldpp_dout(this, 20) << "ERROR: one of policy name or user name is empty" << dendl; return -EINVAL; } return 0; } void RGWGetUserPolicy::execute(optional_yield y) { op_ret = get_params(); if (op_ret < 0) { return; } std::unique_ptr user = driver->get_user(rgw_user(user_name)); op_ret = user->read_attrs(s, s->yield); if (op_ret == -ENOENT) { ldpp_dout(this, 0) << "ERROR: attrs not found for user" << user_name << dendl; op_ret = -ERR_NO_SUCH_ENTITY; return; } if (op_ret == 0) { s->formatter->open_object_section("GetUserPolicyResponse"); s->formatter->open_object_section("ResponseMetadata"); s->formatter->dump_string("RequestId", s->trans_id); s->formatter->close_section(); s->formatter->open_object_section("GetUserPolicyResult"); std::map policies; if (auto it = user->get_attrs().find(RGW_ATTR_USER_POLICY); it != user->get_attrs().end()) { bufferlist bl = it->second; try { decode(policies, bl); } catch (buffer::error& err) { ldpp_dout(this, 0) << "ERROR: failed to decode user policies" << dendl; op_ret = -EIO; return; } if (auto it = policies.find(policy_name); it != policies.end()) { policy = policies[policy_name]; dump(s->formatter); } else { ldpp_dout(this, 0) << "ERROR: policy not found" << policy << dendl; op_ret = -ERR_NO_SUCH_ENTITY; return; } } else { ldpp_dout(this, 0) << "ERROR: RGW_ATTR_USER_POLICY not found" << dendl; op_ret = -ERR_NO_SUCH_ENTITY; return; } s->formatter->close_section(); s->formatter->close_section(); } if (op_ret < 0) { op_ret = -ERR_INTERNAL_ERROR; } } uint64_t RGWListUserPolicies::get_op() { return rgw::IAM::iamListUserPolicies; } int RGWListUserPolicies::get_params() { user_name = s->info.args.get("UserName"); if (user_name.empty()) { ldpp_dout(this, 20) << "ERROR: user name is empty" << dendl; return -EINVAL; } return 0; } void RGWListUserPolicies::execute(optional_yield y) { op_ret = get_params(); if (op_ret < 0) { return; } std::unique_ptr user = driver->get_user(rgw_user(user_name)); op_ret = user->read_attrs(s, s->yield); if (op_ret == -ENOENT) { ldpp_dout(this, 0) << "ERROR: attrs not found for user" << user_name << dendl; op_ret = -ERR_NO_SUCH_ENTITY; return; } if (op_ret == 0) { std::map policies; if (auto it = user->get_attrs().find(RGW_ATTR_USER_POLICY); it != user->get_attrs().end()) { s->formatter->open_object_section("ListUserPoliciesResponse"); s->formatter->open_object_section("ResponseMetadata"); s->formatter->dump_string("RequestId", s->trans_id); s->formatter->close_section(); s->formatter->open_object_section("ListUserPoliciesResult"); bufferlist bl = it->second; try { decode(policies, bl); } catch (buffer::error& err) { ldpp_dout(this, 0) << "ERROR: failed to decode user policies" << dendl; op_ret = -EIO; return; } s->formatter->open_object_section("PolicyNames"); for (const auto& p : policies) { s->formatter->dump_string("member", p.first); } s->formatter->close_section(); s->formatter->close_section(); s->formatter->close_section(); } else { ldpp_dout(this, 0) << "ERROR: RGW_ATTR_USER_POLICY not found" << dendl; op_ret = -ERR_NO_SUCH_ENTITY; return; } } if (op_ret < 0) { op_ret = -ERR_INTERNAL_ERROR; } } uint64_t RGWDeleteUserPolicy::get_op() { return rgw::IAM::iamDeleteUserPolicy; } int RGWDeleteUserPolicy::get_params() { policy_name = s->info.args.get("PolicyName"); user_name = s->info.args.get("UserName"); if (policy_name.empty() || user_name.empty()) { ldpp_dout(this, 20) << "ERROR: One of policy name or user name is empty"<< dendl; return -EINVAL; } return 0; } void RGWDeleteUserPolicy::execute(optional_yield y) { op_ret = get_params(); if (op_ret < 0) { return; } std::unique_ptr user = driver->get_user(rgw_user(user_name)); op_ret = user->load_user(s, s->yield); if (op_ret < 0) { op_ret = -ERR_NO_SUCH_ENTITY; return; } op_ret = user->read_attrs(this, s->yield); if (op_ret == -ENOENT) { op_ret = -ERR_NO_SUCH_ENTITY; return; } ceph::bufferlist in_data; op_ret = driver->forward_request_to_master(this, s->user.get(), nullptr, in_data, nullptr, s->info, y); if (op_ret < 0) { // a policy might've been uploaded to this site when there was no sync // req. in earlier releases, proceed deletion if (op_ret != -ENOENT) { ldpp_dout(this, 5) << "forward_request_to_master returned ret=" << op_ret << dendl; return; } ldpp_dout(this, 0) << "ERROR: forward_request_to_master returned ret=" << op_ret << dendl; } std::map policies; if (auto it = user->get_attrs().find(RGW_ATTR_USER_POLICY); it != user->get_attrs().end()) { bufferlist out_bl = it->second; try { decode(policies, out_bl); } catch (buffer::error& err) { ldpp_dout(this, 0) << "ERROR: failed to decode user policies" << dendl; op_ret = -EIO; return; } if (auto p = policies.find(policy_name); p != policies.end()) { bufferlist in_bl; policies.erase(p); encode(policies, in_bl); user->get_attrs()[RGW_ATTR_USER_POLICY] = in_bl; op_ret = user->store_user(s, s->yield, false); if (op_ret < 0) { op_ret = -ERR_INTERNAL_ERROR; } if (op_ret == 0) { s->formatter->open_object_section("DeleteUserPoliciesResponse"); s->formatter->open_object_section("ResponseMetadata"); s->formatter->dump_string("RequestId", s->trans_id); s->formatter->close_section(); s->formatter->close_section(); } } else { op_ret = -ERR_NO_SUCH_ENTITY; return; } } else { op_ret = -ERR_NO_SUCH_ENTITY; return; } }