]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw/sts: added code to tag, untag and list role tags.
authorPritha Srivastava <prsrivas@redhat.com>
Tue, 1 Jun 2021 16:15:37 +0000 (21:45 +0530)
committerPritha Srivastava <prsrivas@redhat.com>
Wed, 1 Sep 2021 11:39:54 +0000 (17:09 +0530)
The role tags can be used as iam:ResourceTags in AssumeRoleWithWebIdentity
or as aws:PrincipalTags in a session using temporary credentials.

Signed-off-by: Pritha Srivastava <prsrivas@redhat.com>
18 files changed:
src/rgw/rgw_auth_s3.cc
src/rgw/rgw_auth_s3.h
src/rgw/rgw_iam_policy.cc
src/rgw/rgw_iam_policy.h
src/rgw/rgw_op_type.h
src/rgw/rgw_rest_iam.cc
src/rgw/rgw_rest_role.cc
src/rgw/rgw_rest_role.h
src/rgw/rgw_rest_s3.cc
src/rgw/rgw_role.cc
src/rgw/rgw_role.h
src/rgw/rgw_sal.h
src/rgw/rgw_sal_dbstore.cc
src/rgw/rgw_sal_dbstore.h
src/rgw/rgw_sal_rados.cc
src/rgw/rgw_sal_rados.h
src/rgw/rgw_tools.cc
src/rgw/rgw_tools.h

index d6eaf7d127af829cbcb46f37208cd66414fdafad..e46bf32681b8be292f9924bdaffe0e6443524777 100644 (file)
@@ -451,6 +451,40 @@ static inline int parse_v4_auth_header(const req_info& info,               /* in
   return 0;
 }
 
+bool is_non_s3_op(RGWOpType op_type)
+{
+  if (op_type == RGW_STS_GET_SESSION_TOKEN ||
+      op_type == RGW_STS_ASSUME_ROLE ||
+      op_type == RGW_STS_ASSUME_ROLE_WEB_IDENTITY ||
+      op_type == RGW_OP_CREATE_ROLE ||
+      op_type == RGW_OP_DELETE_ROLE ||
+      op_type == RGW_OP_GET_ROLE ||
+      op_type == RGW_OP_MODIFY_ROLE ||
+      op_type == RGW_OP_LIST_ROLES ||
+      op_type == RGW_OP_PUT_ROLE_POLICY ||
+      op_type == RGW_OP_GET_ROLE_POLICY ||
+      op_type == RGW_OP_LIST_ROLE_POLICIES ||
+      op_type == RGW_OP_DELETE_ROLE_POLICY ||
+      op_type == RGW_OP_PUT_USER_POLICY ||
+      op_type == RGW_OP_GET_USER_POLICY ||
+      op_type == RGW_OP_LIST_USER_POLICIES ||
+      op_type == RGW_OP_DELETE_USER_POLICY ||
+      op_type == RGW_OP_CREATE_OIDC_PROVIDER ||
+      op_type == RGW_OP_DELETE_OIDC_PROVIDER ||
+      op_type == RGW_OP_GET_OIDC_PROVIDER ||
+      op_type == RGW_OP_LIST_OIDC_PROVIDERS ||
+      op_type == RGW_OP_PUBSUB_TOPIC_CREATE ||
+      op_type == RGW_OP_PUBSUB_TOPICS_LIST ||
+      op_type == RGW_OP_PUBSUB_TOPIC_GET ||
+      op_type == RGW_OP_PUBSUB_TOPIC_DELETE ||
+      op_type == RGW_OP_TAG_ROLE ||
+      op_type == RGW_OP_LIST_ROLE_TAGS ||
+      op_type == RGW_OP_UNTAG_ROLE) {
+    return true;
+  }
+  return false;
+}
+
 int parse_v4_credentials(const req_info& info,                     /* in */
                         std::string_view& access_key_id,        /* out */
                         std::string_view& credential_scope,     /* out */
index 5ad1516f369a114f528ddc489b894891d1169692..ff28a27fb6d3350b03fa476ed9bc4d80a7433ee3 100644 (file)
@@ -454,6 +454,8 @@ static constexpr char AWS4_UNSIGNED_PAYLOAD_HASH[] = "UNSIGNED-PAYLOAD";
 static constexpr char AWS4_STREAMING_PAYLOAD_HASH[] = \
   "STREAMING-AWS4-HMAC-SHA256-PAYLOAD";
 
+bool is_non_s3_op(RGWOpType op_type);
+
 int parse_v4_credentials(const req_info& info,                     /* in */
                         std::string_view& access_key_id,        /* out */
                         std::string_view& credential_scope,     /* out */
index 41d49791fcb9284bd77e8319f2733a9abb38abcb..c6a63110e62a88e8e69852944a79ce20dc78389c 100644 (file)
@@ -153,6 +153,9 @@ static const actpair actpairs[] =
  { "iam:DeleteOIDCProvider", iamDeleteOIDCProvider},
  { "iam:GetOIDCProvider", iamGetOIDCProvider},
  { "iam:ListOIDCProviders", iamListOIDCProviders},
+ { "iam:TagRole", iamTagRole},
+ { "iam:ListRoleTags", iamListRoleTags},
+ { "iam:UntagRole", iamUntagRole},
  { "sts:AssumeRole", stsAssumeRole},
  { "sts:AssumeRoleWithWebIdentity", stsAssumeRoleWithWebIdentity},
  { "sts:GetSessionToken", stsGetSessionToken},
@@ -1345,6 +1348,15 @@ const char* action_bit_string(uint64_t action) {
   case iamListOIDCProviders:
     return "iam:ListOIDCProviders";
 
+  case iamTagRole:
+    return "iam:TagRole";
+
+  case iamListRoleTags:
+    return "iam:ListRoleTags";
+
+  case iamUntagRole:
+    return "iam:UntagRole";
+
   case stsAssumeRole:
     return "sts:AssumeRole";
 
index b91718789f74c49e384af5c8861bc0a02ad11f00..3689657e4681cc7e9ebcba28f77f8ed46b35bc79 100644 (file)
@@ -128,7 +128,10 @@ static constexpr std::uint64_t iamCreateOIDCProvider = s3All + 14;
 static constexpr std::uint64_t iamDeleteOIDCProvider = s3All + 15;
 static constexpr std::uint64_t iamGetOIDCProvider = s3All + 16;
 static constexpr std::uint64_t iamListOIDCProviders = s3All + 17;
-static constexpr std::uint64_t iamAll = s3All + 18;
+static constexpr std::uint64_t iamTagRole = s3All + 18;
+static constexpr std::uint64_t iamListRoleTags = s3All + 19;
+static constexpr std::uint64_t iamUntagRole = s3All + 20;
+static constexpr std::uint64_t iamAll = s3All + 21;
 
 static constexpr std::uint64_t stsAssumeRole = iamAll + 1;
 static constexpr std::uint64_t stsAssumeRoleWithWebIdentity = iamAll + 2;
index a463b51e02a514b3b070b802524aefb10b8dfaf4..6fe5a564da60962f1f675d4c3e4d04e1ea3f8a75 100644 (file)
@@ -61,6 +61,9 @@ enum RGWOpType {
   RGW_OP_GET_ROLE_POLICY,
   RGW_OP_LIST_ROLE_POLICIES,
   RGW_OP_DELETE_ROLE_POLICY,
+  RGW_OP_TAG_ROLE,
+  RGW_OP_LIST_ROLE_TAGS,
+  RGW_OP_UNTAG_ROLE,
   RGW_OP_PUT_BUCKET_POLICY,
   RGW_OP_GET_BUCKET_POLICY,
   RGW_OP_DELETE_BUCKET_POLICY,
index bbc2e412f5a50ec038b1c918f74b588219abb8de..7b01133fce4a18ce4a5720e8bb613f99fd0b134d 100644 (file)
@@ -79,6 +79,12 @@ RGWOp *RGWHandler_REST_IAM::op_post()
       return new RGWGetOIDCProvider;
     if (action.compare("DeleteOpenIDConnectProvider") == 0)
       return new RGWDeleteOIDCProvider;
+    if (action.compare("TagRole") == 0)
+      return new RGWTagRole;
+    if (action.compare("ListRoleTags") == 0)
+      return new RGWListRoleTags;
+    if (action.compare("UntagRole") == 0)
+      return new RGWUntagRole;
   }
 
   return nullptr;
index 6d89b9873b0170dc0744336e266761c7320ff740..0fa0f8f011554cf755b1aaf36f69ec2edcf3ad25 100644 (file)
@@ -2,6 +2,7 @@
 // vim: ts=8 sw=2 smarttab ft=cpp
 
 #include <errno.h>
+#include <regex>
 
 #include "common/errno.h"
 #include "common/Formatter.h"
@@ -58,6 +59,52 @@ int RGWRestRole::verify_permission(optional_yield y)
   return 0;
 }
 
+int RGWRestRole::parse_tags()
+{
+  vector<string> keys, vals;
+  auto val_map = s->info.args.get_params();
+  const regex pattern_key("Tags.member.([0-9]+).Key");
+  const regex pattern_value("Tags.member.([0-9]+).Value");
+  for (auto& v : val_map) {
+    string key_index="", value_index="";
+    for(sregex_iterator it = sregex_iterator(
+        v.first.begin(), v.first.end(), pattern_key);
+        it != sregex_iterator(); it++) {
+        smatch match;
+        match = *it;
+        key_index = match.str(1);
+        ldout(s->cct, 20) << "Key index: " << match.str(1) << dendl;
+        if (!key_index.empty()) {
+          int index = stoi(key_index);
+          auto pos = keys.begin() + (index-1);
+          keys.insert(pos, v.second);
+        }
+    }
+    for(sregex_iterator it = sregex_iterator(
+        v.first.begin(), v.first.end(), pattern_value);
+        it != sregex_iterator(); it++) {
+        smatch match;
+        match = *it;
+        value_index = match.str(1);
+        ldout(s->cct, 20) << "Value index: " << match.str(1) << dendl;
+        if (!value_index.empty()) {
+          int index = stoi(value_index);
+          auto pos = vals.begin() + (index-1);
+          vals.insert(pos, v.second);
+        }
+    }
+  }
+  if (keys.size() != vals.size()) {
+    ldout(s->cct, 0) << "No. of keys doesn't match with no. of values in tags" << dendl;
+    return -EINVAL;
+  }
+  for (size_t i = 0; i < keys.size(); i++) {
+    tags.emplace(keys[i], vals[i]);
+    ldout(s->cct, 0) << "Tag Key: " << keys[i] << " Tag Value is: " << vals[i] << dendl;
+  }
+  return 0;
+}
+
 void RGWRestRole::send_response()
 {
   if (op_ret) {
@@ -124,6 +171,16 @@ int RGWCreateRole::get_params()
     return -ERR_MALFORMED_DOC;
   }
 
+  int ret = parse_tags();
+  if (ret < 0) {
+    return ret;
+  }
+
+  if (tags.size() > 50) {
+    ldout(s->cct, 0) << "No. tags is greater than 50" << dendl;
+    return -EINVAL;
+  }
+
   return 0;
 }
 
@@ -138,7 +195,8 @@ void RGWCreateRole::execute(optional_yield y)
                                                            user_tenant,
                                                            role_path,
                                                            trust_policy,
-                                                           max_session_duration);
+                                                           max_session_duration,
+                       tags);
   if (!user_tenant.empty() && role->get_tenant() != user_tenant) {
     ldpp_dout(this, 20) << "ERROR: the tenant provided in the role name does not match with the tenant of the user creating the role"
     << dendl;
@@ -146,7 +204,6 @@ void RGWCreateRole::execute(optional_yield y)
     return;
   }
   op_ret = role->create(s, true, y);
-
   if (op_ret == -EEXIST) {
     op_ret = -ERR_ROLE_EXISTS;
   }
@@ -503,3 +560,118 @@ void RGWDeleteRolePolicy::execute(optional_yield y)
   s->formatter->close_section();
   s->formatter->close_section();
 }
+
+int RGWTagRole::get_params()
+{
+  role_name = s->info.args.get("RoleName");
+
+  if (role_name.empty()) {
+    ldout(s->cct, 0) << "ERROR: Role name is empty" << dendl;
+    return -EINVAL;
+  }
+  int ret = parse_tags();
+  if (ret < 0) {
+    return ret;
+  }
+
+  return 0;
+}
+
+void RGWTagRole::execute(optional_yield y)
+{
+  op_ret = get_params();
+  if (op_ret < 0) {
+    return;
+  }
+
+  op_ret = _role->set_tags(this, tags);
+  if (op_ret == 0) {
+    op_ret = _role->update(this, y);
+  }
+
+  if (op_ret == 0) {
+    s->formatter->open_object_section("TagRoleResponse");
+    s->formatter->open_object_section("ResponseMetadata");
+    s->formatter->dump_string("RequestId", s->trans_id);
+    s->formatter->close_section();
+    s->formatter->close_section();
+  }
+}
+
+int RGWListRoleTags::get_params()
+{
+  role_name = s->info.args.get("RoleName");
+
+  if (role_name.empty()) {
+    ldout(s->cct, 0) << "ERROR: Role name is empty" << dendl;
+    return -EINVAL;
+  }
+
+  return 0;
+}
+
+void RGWListRoleTags::execute(optional_yield y)
+{
+  op_ret = get_params();
+  if (op_ret < 0) {
+    return;
+  }
+
+  boost::optional<multimap<string,string>> tag_map = _role->get_tags();
+  s->formatter->open_object_section("ListRoleTagsResponse");
+  s->formatter->open_object_section("ListRoleTagsResult");
+  if (tag_map) {
+    s->formatter->open_array_section("Tags");
+    for (const auto& it : tag_map.get()) {
+      s->formatter->open_object_section("Key");
+      encode_json("Key", it.first, s->formatter);
+      s->formatter->close_section();
+      s->formatter->open_object_section("Value");
+      encode_json("Value", it.second, s->formatter);
+      s->formatter->close_section();
+    }
+    s->formatter->close_section();
+  }
+  s->formatter->close_section();
+  s->formatter->open_object_section("ResponseMetadata");
+  s->formatter->dump_string("RequestId", s->trans_id);
+  s->formatter->close_section();
+  s->formatter->close_section();
+}
+
+int RGWUntagRole::get_params()
+{
+  role_name = s->info.args.get("RoleName");
+
+  if (role_name.empty()) {
+    ldout(s->cct, 0) << "ERROR: Role name is empty" << dendl;
+    return -EINVAL;
+  }
+
+  auto val_map = s->info.args.get_params();
+  for (auto& it : val_map) {
+    if (it.first.find("TagKeys.member.") != string::npos) {
+        tagKeys.emplace_back(it.second);
+    }
+  }
+  return 0;
+}
+
+void RGWUntagRole::execute(optional_yield y)
+{
+  op_ret = get_params();
+  if (op_ret < 0) {
+    return;
+  }
+
+  _role->erase_tags(tagKeys);
+  op_ret = _role->update(this, y);
+
+  if (op_ret == 0) {
+    s->formatter->open_object_section("UntagRoleResponse");
+    s->formatter->open_object_section("ResponseMetadata");
+    s->formatter->dump_string("RequestId", s->trans_id);
+    s->formatter->close_section();
+    s->formatter->close_section();
+  }
+}
\ No newline at end of file
index 30bf0446bb8a2eff1cac637840e6410a64022885..a8beb2b54052c2fbb44201db769e6b618d42e049 100644 (file)
@@ -17,11 +17,13 @@ protected:
   std::string perm_policy;
   std::string path_prefix;
   std::string max_session_duration;
+  std::multimap<std::string,std::string> tags;
+  std::vector<std::string> tagKeys;
   std::unique_ptr<rgw::sal::RGWRole> _role;
-public:
   int verify_permission(optional_yield y) override;
   void send_response() override;
   virtual uint64_t get_op() = 0;
+  int parse_tags();
 };
 
 class RGWRoleRead : public RGWRestRole {
@@ -129,3 +131,33 @@ public:
   RGWOpType get_type() override { return RGW_OP_DELETE_ROLE_POLICY; }
   uint64_t get_op() override { return rgw::IAM::iamDeleteRolePolicy; }
 };
+
+class RGWTagRole : public RGWRoleWrite {
+public:
+  RGWTagRole() = default;
+  void execute(optional_yield y) override;
+  int get_params();
+  const char* name() const override { return "tag_role"; }
+  RGWOpType get_type() override { return RGW_OP_TAG_ROLE; }
+  uint64_t get_op() override { return rgw::IAM::iamTagRole; }
+};
+
+class RGWListRoleTags : public RGWRoleRead {
+public:
+  RGWListRoleTags() = default;
+  void execute(optional_yield y) override;
+  int get_params();
+  const char* name() const override { return "list_role_tags"; }
+  RGWOpType get_type() override { return RGW_OP_LIST_ROLE_TAGS; }
+  uint64_t get_op() override { return rgw::IAM::iamListRoleTags; }
+};
+
+class RGWUntagRole : public RGWRoleWrite {
+public:
+  RGWUntagRole() = default;
+  void execute(optional_yield y) override;
+  int get_params();
+  const char* name() const override { return "untag_role"; }
+  RGWOpType get_type() override { return RGW_OP_UNTAG_ROLE; }
+  uint64_t get_op() override { return rgw::IAM::iamUntagRole; }
+};
index b7ee647e727d65258d582c390ce40181bde5331a..d9fcd8dc1330c0e52065a1e9ebd070a2885ba7af 100644 (file)
@@ -5408,33 +5408,7 @@ AWSGeneralAbstractor::get_auth_data_v4(const req_state* const s,
     throw -EPERM;
   }
 
-  bool is_non_s3_op = false;
-  if (s->op_type == RGW_STS_GET_SESSION_TOKEN ||
-      s->op_type == RGW_STS_ASSUME_ROLE ||
-      s->op_type == RGW_STS_ASSUME_ROLE_WEB_IDENTITY ||
-      s->op_type == RGW_OP_CREATE_ROLE ||
-      s->op_type == RGW_OP_DELETE_ROLE ||
-      s->op_type == RGW_OP_GET_ROLE ||
-      s->op_type == RGW_OP_MODIFY_ROLE ||
-      s->op_type == RGW_OP_LIST_ROLES ||
-      s->op_type == RGW_OP_PUT_ROLE_POLICY ||
-      s->op_type == RGW_OP_GET_ROLE_POLICY ||
-      s->op_type == RGW_OP_LIST_ROLE_POLICIES ||
-      s->op_type == RGW_OP_DELETE_ROLE_POLICY ||
-      s->op_type == RGW_OP_PUT_USER_POLICY ||
-      s->op_type == RGW_OP_GET_USER_POLICY ||
-      s->op_type == RGW_OP_LIST_USER_POLICIES ||
-      s->op_type == RGW_OP_DELETE_USER_POLICY ||
-      s->op_type == RGW_OP_CREATE_OIDC_PROVIDER ||
-      s->op_type == RGW_OP_DELETE_OIDC_PROVIDER ||
-      s->op_type == RGW_OP_GET_OIDC_PROVIDER ||
-      s->op_type == RGW_OP_LIST_OIDC_PROVIDERS ||
-      s->op_type == RGW_OP_PUBSUB_TOPIC_CREATE ||
-      s->op_type == RGW_OP_PUBSUB_TOPICS_LIST ||
-      s->op_type == RGW_OP_PUBSUB_TOPIC_GET ||
-      s->op_type == RGW_OP_PUBSUB_TOPIC_DELETE) {
-    is_non_s3_op = true;
-  }
+  bool is_non_s3_op = rgw::auth::s3::is_non_s3_op(s->op_type);
 
   const char* exp_payload_hash = nullptr;
   string payload_hash;
index 804fa892d831dc4bc2d3476827fcc04426cbe930..fe028f315971ea1a7f18f2e68ba1ffacf8f8c5b6 100644 (file)
@@ -119,6 +119,18 @@ void RGWRole::dump(Formatter *f) const
   encode_json("CreateDate", creation_date, f);
   encode_json("MaxSessionDuration", max_session_duration, f);
   encode_json("AssumeRolePolicyDocument", trust_policy, f);
+  if (!tags.empty()) {
+    f->open_array_section("Tags");
+    for (const auto& it : tags) {
+      f->open_object_section("Key");
+      encode_json("Key", it.first, f);
+      f->close_section();
+      f->open_object_section("Value");
+      encode_json("Value", it.second, f);
+      f->close_section();
+    }
+    f->close_section();
+  }
 }
 
 void RGWRole::decode_json(JSONObj *obj)
@@ -178,6 +190,33 @@ void RGWRole::update_trust_policy(string& trust_policy)
   this->trust_policy = trust_policy;
 }
 
+int RGWRole::set_tags(const DoutPrefixProvider* dpp, const multimap<string,string>& tags_map)
+{
+  for (auto& it : tags_map) {
+    this->tags.emplace(it.first, it.second);
+  }
+  if (this->tags.size() > 50) {
+    ldpp_dout(dpp, 0) << "No. of tags is greater than 50" << dendl;
+    return -EINVAL;
+  }
+  return 0;
+}
+
+boost::optional<multimap<string,string>> RGWRole::get_tags()
+{
+  if(this->tags.empty()) {
+    return boost::none;
+  }
+  return this->tags;
+}
+
+void RGWRole::erase_tags(const vector<string>& tagKeys)
+{
+  for (auto& it : tagKeys) {
+    this->tags.erase(it);
+  }
+}
+
 const string& RGWRole::get_names_oid_prefix()
 {
   return role_name_oid_prefix;
index 0563db8a27ff4c95bd6b37e6ec915d9b12dab8ce..1d85dc1f06840398640fa12055acf1eaa1236755 100644 (file)
@@ -37,6 +37,7 @@ protected:
   std::map<std::string, std::string> perm_policy_map;
   std::string tenant;
   uint64_t max_session_duration;
+  std::multimap<std::string,std::string> tags;
 
 public:
   virtual int store_info(const DoutPrefixProvider *dpp, bool exclusive, optional_yield y) = 0;
@@ -52,11 +53,13 @@ public:
           std::string tenant,
           std::string path="",
           std::string trust_policy="",
-          std::string max_session_duration_str="")
+          std::string max_session_duration_str="",
+          std::multimap<std::string,std::string> tags={})
   : name(std::move(name)),
     path(std::move(path)),
     trust_policy(std::move(trust_policy)),
-    tenant(std::move(tenant)) {
+    tenant(std::move(tenant)),
+    tags(std::move(tags)) {
     if (this->path.empty())
       this->path = "/";
     extract_name_tenant(this->name);
@@ -86,7 +89,7 @@ public:
   }
 
   void decode(bufferlist::const_iterator& bl) {
-    DECODE_START(2, bl);
+    DECODE_START(3, bl);
     decode(id, bl);
     decode(name, bl);
     decode(path, bl);
@@ -123,6 +126,9 @@ public:
   std::vector<std::string> get_role_policy_names();
   int get_role_policy(const DoutPrefixProvider* dpp, const std::string& policy_name, std::string& perm_policy);
   int delete_policy(const DoutPrefixProvider* dpp, const std::string& policy_name);
+  int set_tags(const DoutPrefixProvider* dpp, const std::multimap<std::string,std::string>& tags_map);
+  boost::optional<std::multimap<std::string,std::string>> get_tags();
+  void erase_tags(const std::vector<std::string>& tagKeys);
   void dump(Formatter *f) const;
   void decode_json(JSONObj *obj);
 
index b1b9922f8bd10922c2b5d2c52183bae74f71dd4e..68120239214bf47b88389a5d2481b5cad7b908a3 100644 (file)
@@ -246,7 +246,8 @@ class Store {
                                              std::string tenant,
                                              std::string path="",
                                              std::string trust_policy="",
-                                             std::string max_session_duration_str="") = 0;
+                                             std::string max_session_duration_str="",
+                std::multimap<std::string,std::string> tags={}) = 0;
     virtual std::unique_ptr<RGWRole> get_role(std::string id) = 0;
     virtual int get_roles(const DoutPrefixProvider *dpp,
                          optional_yield y,
index 898b10dd6505cc516476a746bb1f29e455c1a8a3..a28610f949f6556c8ea684b834c03f938fb0477a 100644 (file)
@@ -424,7 +424,8 @@ namespace rgw::sal {
       std::string tenant,
       std::string path,
       std::string trust_policy,
-      std::string max_session_duration_str)
+      std::string max_session_duration_str,
+      std::multimap<std::string,std::string> tags)
   {
     RGWRole* p = nullptr;
     return std::unique_ptr<RGWRole>(p);
index 50129d9f7ed606fbecaf7aff90c2c484501e413c..5d417b5defac6db0bdddd9c226b6973d7af75f0c 100644 (file)
@@ -336,11 +336,12 @@ namespace rgw { namespace sal {
       virtual std::string get_host_id() { return ""; }
 
       virtual std::unique_ptr<LuaScriptManager> get_lua_script_manager() override;
-      virtual std::unique_ptr<RGWRole> get_role(string name,
-          string tenant,
-          string path="",
-          string trust_policy="",
-          string max_session_duration_str="") override;
+      virtual std::unique_ptr<RGWRole> get_role(std::string name,
+          std::string tenant,
+          std::string path="",
+          std::string trust_policy="",
+          std::string max_session_duration_str="",
+          std::multimap<std::string,std::string> tags={}) override;
       virtual std::unique_ptr<RGWRole> get_role(std::string id) override;
       virtual int get_roles(const DoutPrefixProvider *dpp,
           optional_yield y,
index d75069c9727ec688029d69b4c03bddbb86325914..ae11e36a6d6ee80f26b9759ad12c2cc52595bc5f 100644 (file)
@@ -1318,9 +1318,10 @@ std::unique_ptr<RGWRole> RadosStore::get_role(std::string name,
                                              std::string tenant,
                                              std::string path,
                                              std::string trust_policy,
-                                             std::string max_session_duration_str)
+                                             std::string max_session_duration_str,
+                std::multimap<std::string,std::string> tags)
 {
-  return std::make_unique<RadosRole>(this, name, tenant, path, trust_policy, max_session_duration_str);
+  return std::make_unique<RadosRole>(this, name, tenant, path, trust_policy, max_session_duration_str, tags);
 }
 
 std::unique_ptr<RGWRole> RadosStore::get_role(std::string id)
@@ -2868,6 +2869,14 @@ int RadosRole::store_info(const DoutPrefixProvider *dpp, bool exclusive, optiona
   bufferlist bl;
   encode(*this, bl);
 
+  if (!this->tags.empty()) {
+    bufferlist bl_tags;
+    encode(this->tags, bl_tags);
+    map<string, bufferlist> attrs;
+    attrs.emplace("tagging", bl_tags);
+    return rgw_put_system_obj(dpp, obj_ctx, store->get_zone()->get_params().roles_pool, oid, bl, exclusive, nullptr, real_time(), y, &attrs);
+  }
+
   return rgw_put_system_obj(dpp, obj_ctx, store->get_zone()->get_params().roles_pool, oid, bl, exclusive, nullptr, real_time(), y);
 }
 
@@ -2952,7 +2961,8 @@ int RadosRole::read_info(const DoutPrefixProvider *dpp, optional_yield y)
   std::string oid = get_info_oid_prefix() + id;
   bufferlist bl;
 
-  int ret = rgw_get_system_obj(obj_ctx, store->get_zone()->get_params().roles_pool, oid, bl, nullptr, nullptr, null_yield, dpp);
+  map<string, bufferlist> attrs;
+  int ret = rgw_get_system_obj(obj_ctx, store->get_zone()->get_params().roles_pool, oid, bl, nullptr, nullptr, null_yield, dpp, &attrs, nullptr, boost::none, true);
   if (ret < 0) {
     ldpp_dout(dpp, 0) << "ERROR: failed reading role info from Role pool: " << id << ": " << cpp_strerror(-ret) << dendl;
     return ret;
@@ -2967,6 +2977,19 @@ int RadosRole::read_info(const DoutPrefixProvider *dpp, optional_yield y)
     return -EIO;
   }
 
+  auto it = attrs.find("tagging");
+  if (it != attrs.end()) {
+    bufferlist bl_tags = it->second;
+    try {
+      using ceph::decode;
+      auto iter = bl_tags.cbegin();
+      decode(tags, iter);
+    } catch (buffer::error& err) {
+      ldpp_dout(dpp, 0) << "ERROR: failed to decode attrs" << id << dendl;
+      return -EIO;
+    }
+  }
+
   return 0;
 }
 
index d7472886d7612f88ed97bf089dc5a977ed46d309..14b486b1df27ca2cc2f08ee5b3b206c7f7bac309 100644 (file)
@@ -431,7 +431,8 @@ class RadosStore : public Store {
                                              std::string tenant,
                                              std::string path="",
                                              std::string trust_policy="",
-                                             std::string max_session_duration_str="") override;
+                                             std::string max_session_duration_str="",
+                std::multimap<std::string,std::string> tags={}) override;
     virtual std::unique_ptr<RGWRole> get_role(std::string id) override;
     virtual int get_roles(const DoutPrefixProvider *dpp,
                          optional_yield y,
@@ -778,7 +779,8 @@ public:
           std::string tenant,
           std::string path,
           std::string trust_policy,
-          std::string max_session_duration) : RGWRole(name, tenant, path, trust_policy, max_session_duration), store(_store) {}
+          std::string max_session_duration,
+          std::multimap<std::string,std::string> tags) : RGWRole(name, tenant, path, trust_policy, max_session_duration, tags), store(_store) {}
   RadosRole(RadosStore* _store, std::string id) : RGWRole(id), store(_store) {}
   ~RadosRole() = default;
 
index 7073e5c5aa5518a29a3ba2ee4e6017532da36c0e..105fcc0579c1a90e14a667056ed18ca225bdb694 100644 (file)
@@ -183,7 +183,7 @@ int rgw_put_system_obj(const DoutPrefixProvider *dpp,
 int rgw_get_system_obj(RGWSysObjectCtx& obj_ctx, const rgw_pool& pool, const string& key, bufferlist& bl,
                        RGWObjVersionTracker *objv_tracker, real_time *pmtime, optional_yield y, const DoutPrefixProvider *dpp, map<string, bufferlist> *pattrs,
                        rgw_cache_entry_info *cache_info,
-                      boost::optional<obj_version> refresh_version)
+                      boost::optional<obj_version> refresh_version, bool raw_attrs)
 {
   bufferlist::iterator iter;
   int request_len = READ_CHUNK_LEN;
@@ -201,6 +201,7 @@ int rgw_get_system_obj(RGWSysObjectCtx& obj_ctx, const rgw_pool& pool, const str
     int ret = rop.set_attrs(pattrs)
                  .set_last_mod(pmtime)
                  .set_objv_tracker(objv_tracker)
+                 .set_raw_attrs(raw_attrs)
                  .stat(y, dpp);
     if (ret < 0)
       return ret;
index a1607ca663f8c99fd8ba4905abc7ebc5aab5d1a4..df17f3914df06b84641f976e8094c592c32480bc 100644 (file)
@@ -77,7 +77,7 @@ int rgw_put_system_obj(const DoutPrefixProvider *dpp, RGWSysObjectCtx& obj_ctx,
 int rgw_get_system_obj(RGWSysObjectCtx& obj_ctx, const rgw_pool& pool, const std::string& key, bufferlist& bl,
                        RGWObjVersionTracker *objv_tracker, real_time *pmtime, optional_yield y, const DoutPrefixProvider *dpp, std::map<std::string, bufferlist> *pattrs = NULL,
                        rgw_cache_entry_info *cache_info = NULL,
-                      boost::optional<obj_version> refresh_version = boost::none);
+                      boost::optional<obj_version> refresh_version = boost::none, bool raw_attrs=false);
 int rgw_delete_system_obj(const DoutPrefixProvider *dpp, 
                           RGWSI_SysObj *sysobj_svc, const rgw_pool& pool, const std::string& oid,
                           RGWObjVersionTracker *objv_tracker, optional_yield y);