--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+#include <errno.h>
+#include <regex>
+
+#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"
+
+#define dout_subsys ceph_subsys_rgw
+
+using rgw::IAM::Policy;
+
+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()
+{
+ int ret = check_caps(s->user->caps);
+ ldout(s->cct, 0) << "INFO: verify_permissions ret" << ret << dendl;
+ return ret;
+}
+
+bool RGWRestUserPolicy::validate_input()
+{
+ if (policy_name.length() > MAX_POLICY_NAME_LEN) {
+ ldout(s->cct, 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)) {
+ ldout(s->cct, 0) << "ERROR: Invalid chars in policy name " << dendl;
+ return false;
+ }
+
+ return true;
+}
+
+int RGWUserPolicyRead::check_caps(RGWUserCaps& caps)
+{
+ return caps.check_cap("user-policy", RGW_CAP_READ);
+}
+
+int RGWUserPolicyWrite::check_caps(RGWUserCaps& caps)
+{
+ return caps.check_cap("user-policy", RGW_CAP_WRITE);
+}
+
+int RGWPutUserPolicy::get_params()
+{
+ policy_name = s->info.args.get("PolicyName");
+ user_name = s->info.args.get("UserName");
+ policy = s->info.args.get("PolicyDocument");
+
+ if (policy_name.empty() || user_name.empty() || policy.empty()) {
+ ldout(s->cct, 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()
+{
+ op_ret = get_params();
+ if (op_ret < 0) {
+ return;
+ }
+
+ bufferlist bl = bufferlist::static_from_string(policy);
+ ldout(s->cct, 0) << "policy: " << policy << dendl;
+ ldout(s->cct, 0) << "bufferlist: " << bl.c_str() << dendl;
+
+ RGWUserInfo info;
+ rgw_user user_id(user_name);
+ op_ret = rgw_get_user_info_by_uid(store, user_id, info);
+ if (op_ret < 0) {
+ op_ret = -ERR_NO_SUCH_ENTITY;
+ return;
+ }
+
+ map<string, bufferlist> uattrs;
+ op_ret = rgw_get_user_attrs_by_uid(store, user_id, uattrs);
+ if (op_ret == -ENOENT) {
+ op_ret = -ERR_NO_SUCH_ENTITY;
+ return;
+ }
+
+ try {
+ const Policy p(s->cct, s->user->user_id.tenant, bl);
+ map<string, string> policies;
+ if (auto it = uattrs.find(RGW_ATTR_USER_POLICY); it != uattrs.end()) {
+ bufferlist out_bl = uattrs[RGW_ATTR_USER_POLICY];
+ decode(policies, out_bl);
+ }
+ bufferlist in_bl;
+ policies[policy_name] = policy;
+ encode(policies, in_bl);
+ uattrs[RGW_ATTR_USER_POLICY] = in_bl;
+
+ RGWObjVersionTracker objv_tracker;
+ op_ret = rgw_store_user_info(store, info, &info, &objv_tracker, real_time(), false, &uattrs);
+ if (op_ret < 0) {
+ op_ret = -ERR_INTERNAL_ERROR;
+ }
+ } catch (rgw::IAM::PolicyParseException& e) {
+ ldout(s->cct, 20) << "failed to parse policy: " << e.what() << dendl;
+ op_ret = -ERR_MALFORMED_DOC;
+ }
+ ldout(s->cct, 20) << "op_ret is : " << op_ret << dendl;
+}
+
+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()) {
+ ldout(s->cct, 20) << "ERROR: one of policy name or user name is empty"
+ << dendl;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void RGWGetUserPolicy::execute()
+{
+ op_ret = get_params();
+ if (op_ret < 0) {
+ return;
+ }
+
+ rgw_user user_id(user_name);
+ map<string, bufferlist> uattrs;
+ op_ret = rgw_get_user_attrs_by_uid(store, user_id, uattrs);
+ if (op_ret == -ENOENT) {
+ ldout(s->cct, 0) << "ERROR: attrs not found for user" << user_name << dendl;
+ op_ret = -ERR_NO_SUCH_ENTITY;
+ return;
+ }
+
+ if (op_ret == 0) {
+ map<string, string> policies;
+ if (auto it = uattrs.find(RGW_ATTR_USER_POLICY); it != uattrs.end()) {
+ bufferlist bl = uattrs[RGW_ATTR_USER_POLICY];
+ decode(policies, bl);
+ if (auto it = policies.find(policy_name); it != policies.end()) {
+ policy = policies[policy_name];
+ s->formatter->open_object_section("userpolicy");
+ dump(s->formatter);
+ s->formatter->close_section();
+ } else {
+ ldout(s->cct, 0) << "ERROR: policy not found" << policy << dendl;
+ op_ret = -ERR_NO_SUCH_ENTITY;
+ return;
+ }
+ } else {
+ ldout(s->cct, 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;
+ }
+}
+
+int RGWListUserPolicies::get_params()
+{
+ user_name = s->info.args.get("UserName");
+
+ if (user_name.empty()) {
+ ldout(s->cct, 20) << "ERROR: user name is empty" << dendl;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void RGWListUserPolicies::execute()
+{
+ op_ret = get_params();
+ if (op_ret < 0) {
+ return;
+ }
+
+ rgw_user user_id(user_name);
+ map<string, bufferlist> uattrs;
+ op_ret = rgw_get_user_attrs_by_uid(store, user_id, uattrs);
+ if (op_ret == -ENOENT) {
+ ldout(s->cct, 0) << "ERROR: attrs not found for user" << user_name << dendl;
+ op_ret = -ERR_NO_SUCH_ENTITY;
+ return;
+ }
+
+ if (op_ret == 0) {
+ map<string, string> policies;
+ if (auto it = uattrs.find(RGW_ATTR_USER_POLICY); it != uattrs.end()) {
+ bufferlist bl = uattrs[RGW_ATTR_USER_POLICY];
+ decode(policies, bl);
+ for (const auto& p : policies) {
+ s->formatter->open_object_section("policies");
+ s->formatter->dump_string("policy", p.first);
+ s->formatter->close_section();
+ }
+ } else {
+ ldout(s->cct, 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;
+ }
+}
+
+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()) {
+ ldout(s->cct, 20) << "ERROR: One of policy name or user name is empty"<< dendl;
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void RGWDeleteUserPolicy::execute()
+{
+ op_ret = get_params();
+ if (op_ret < 0) {
+ return;
+ }
+
+ RGWUserInfo info;
+ rgw_user user_id(user_name);
+ op_ret = rgw_get_user_info_by_uid(store, user_id, info);
+ if (op_ret < 0) {
+ op_ret = -ERR_NO_SUCH_ENTITY;
+ return;
+ }
+
+ map<string, bufferlist> uattrs;
+ op_ret = rgw_get_user_attrs_by_uid(store, user_id, uattrs);
+ if (op_ret == -ENOENT) {
+ op_ret = -ERR_NO_SUCH_ENTITY;
+ return;
+ }
+
+ map<string, string> policies;
+ if (auto it = uattrs.find(RGW_ATTR_USER_POLICY); it != uattrs.end()) {
+ bufferlist out_bl = uattrs[RGW_ATTR_USER_POLICY];
+ decode(policies, out_bl);
+
+ if (auto p = policies.find(policy_name); p != policies.end()) {
+ bufferlist in_bl;
+ policies.erase(p);
+ encode(policies, in_bl);
+ uattrs[RGW_ATTR_USER_POLICY] = in_bl;
+
+ RGWObjVersionTracker objv_tracker;
+ op_ret = rgw_store_user_info(store, info, &info, &objv_tracker, real_time(), false, &uattrs);
+ if (op_ret < 0) {
+ op_ret = -ERR_INTERNAL_ERROR;
+ }
+ } else {
+ op_ret = -ERR_NO_SUCH_ENTITY;
+ return;
+ }
+ } else {
+ op_ret = -ERR_NO_SUCH_ENTITY;
+ return;
+ }
+}
\ No newline at end of file
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+#ifndef CEPH_RGW_REST_USER_POLICY_H
+#define CEPH_RGW_REST_USER_POLICY_H
+
+class RGWRestUserPolicy : public RGWRESTOp {
+protected:
+ static constexpr int MAX_POLICY_NAME_LEN = 128;
+ string policy_name;
+ string user_name;
+ string policy;
+
+ bool validate_input();
+
+public:
+ int verify_permission() override;
+ void send_response() override;
+ void dump(Formatter *f) const;
+};
+
+class RGWUserPolicyRead : public RGWRestUserPolicy {
+public:
+ RGWUserPolicyRead() = default;
+ int check_caps(RGWUserCaps& caps) override;
+};
+
+class RGWUserPolicyWrite : public RGWRestUserPolicy {
+public:
+ RGWUserPolicyWrite() = default;
+ int check_caps(RGWUserCaps& caps) override;
+};
+
+class RGWPutUserPolicy : public RGWUserPolicyWrite {
+public:
+ RGWPutUserPolicy() = default;
+ void execute() override;
+ int get_params();
+ const char* name() const override { return "put_user-policy"; }
+ RGWOpType get_type() override { return RGW_OP_PUT_USER_POLICY; }
+};
+
+class RGWGetUserPolicy : public RGWUserPolicyRead {
+public:
+ RGWGetUserPolicy() = default;
+ void execute() override;
+ int get_params();
+ const char* name() const override { return "get_user_policy"; }
+ RGWOpType get_type() override { return RGW_OP_GET_USER_POLICY; }
+};
+
+class RGWListUserPolicies : public RGWUserPolicyRead {
+public:
+ RGWListUserPolicies() = default;
+ void execute() override;
+ int get_params();
+ const char* name() const override { return "list_user_policies"; }
+ RGWOpType get_type() override { return RGW_OP_LIST_USER_POLICIES; }
+};
+
+class RGWDeleteUserPolicy : public RGWUserPolicyWrite {
+public:
+ RGWDeleteUserPolicy() = default;
+ void execute() override;
+ int get_params();
+ const char* name() const override { return "delete_user_policy"; }
+ RGWOpType get_type() override { return RGW_OP_DELETE_USER_POLICY; }
+};
+
+#endif /* CEPH_RGW_REST_USER_POLICY_H */
+