]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: add new cap user-without-keys wip-rgw-add-cap-user-without-keys
authorAli Maredia <amaredia@redhat.com>
Fri, 5 Jan 2024 19:21:17 +0000 (19:21 +0000)
committerAli Maredia <amaredia@redhat.com>
Fri, 5 Jan 2024 19:21:17 +0000 (19:21 +0000)
This new cap removes S3 keys and Swift keys from
the response in the admin api command 'get user info'.

Signed-off-by: Ali Maredia <amaredia@redhat.com>
doc/radosgw/admin.rst
doc/radosgw/adminops.rst
qa/tasks/radosgw_admin_rest.py
src/rgw/driver/rados/rgw_rest_user.cc
src/rgw/driver/rados/rgw_user.cc
src/rgw/driver/rados/rgw_user.h
src/rgw/rgw_common.cc

index f922ad2b8df606ffb7fc8dd1d3dbf8096fc3deb6..c80d500b391e4c34e8e6ac971d110f15d69d970d 100644 (file)
@@ -369,7 +369,7 @@ To add administrative capabilities to a user, execute the following::
 You can add read, write or all capabilities to users, buckets, metadata and 
 usage (utilization). For example::
 
-       --caps="[users|buckets|metadata|usage|zone|amz-cache|info|bilog|mdlog|datalog|user-policy|oidc-provider|roles|ratelimit]=[*|read|write|read, write]"
+       --caps="[users|buckets|metadata|usage|zone|amz-cache|info|bilog|mdlog|datalog|user-policy|oidc-provider|roles|ratelimit|users-without-keys]=[*|read|write|read, write]"
 
 For example::
 
index 0974b95c5862b4d22443ad70982b3e12c5f2376d..4bf5d9beeef46178967e2f5b25833eba2fd810fe 100644 (file)
@@ -273,10 +273,12 @@ TBD.
 Get User Info
 =============
 
-Get user information.
+Get user information. Cap ``users`` must be set to ``read`` to run this operation. 
+If additional cap ``users-without-keys`` is set to ``read`` or ``*``, S3 Key and Swift keys will not be
+included in the response unless the user running this operation is the system user.
 
 :caps: users=read
-
+:optional cap: users-without-keys=read
 
 Syntax
 ~~~~~~
@@ -341,12 +343,14 @@ If successful, the response contains the user information.
 ``keys``
 
 :Description: S3 keys associated with this user account.
+              If the optional cap ``users-without-keys`` is set to ``read``, S3 keys are not in the response.
 :Type: Container
 :Parent: ``user``
 
 ``swift_keys``
 
 :Description: Swift keys associated with this user account.
+              If the optional cap ``users-without-keys`` is set to ``read``, Swift keys are not in the response.
 :Type: Container
 :Parent: ``user``
 
index 3de4d6bc92587890dbe6c2999a8830565f96d88e..d91a086c8e9aef51e895d6b04f0d3ea6ed3e9557 100644 (file)
@@ -291,6 +291,67 @@ def task(ctx, config):
     assert out['type'] == 'rgw'
     assert out['mfa_ids'] == []
 
+    # TESTCASE 'info-existing','user','info','existing user','returns no keys with users-without-keys cap set to read'
+    (err, out) = rgwadmin(ctx, client, [
+            'caps', 'add',
+            '--uid', admin_user,
+            '--caps', 'users-without-keys=read'
+            ])
+    logging.error(out)
+    logging.error(err)
+    assert not err
+
+    (ret, out) = rgwadmin_rest(admin_conn, ['user', 'info'], {'uid' : user1})
+    assert 'keys' in out
+    assert 'swift_keys' in out
+
+    # TESTCASE 'info-existing','user','info','existing user','returns no keys with users-without-keys cap set to read'
+    (err, out) = rgwadmin(ctx, client, [
+            'caps', 'add',
+            '--uid', admin_user,
+            '--caps', 'users-without-keys=*'
+            ])
+    logging.error(out)
+    logging.error(err)
+    assert not err
+
+    (ret, out) = rgwadmin_rest(admin_conn, ['user', 'info'], {'uid' : user1})
+    assert 'keys' in out
+    assert 'swift_keys' in out
+
+    # TESTCASE 'info-existing','user','info','existing user','returns keys with users-without-keys cap set to write'
+    (err, out) = rgwadmin(ctx, client, [
+            'caps', 'rm',
+            '--uid', admin_user,
+            '--caps', 'users-without-keys=*'
+            ])
+    logging.error(out)
+    logging.error(err)
+    assert not err
+
+    (err, out) = rgwadmin(ctx, client, [
+            'caps', 'add',
+            '--uid', admin_user,
+            '--caps', 'users-without-keys=write'
+            ])
+    logging.error(out)
+    logging.error(err)
+    assert not err
+
+    (ret, out) = rgwadmin_rest(admin_conn, ['user', 'info'], {'uid' : user1})
+    assert len(out['keys']) == 1
+    assert out['swift_keys'] == []
+
+    # remove cap users-without-keys permenantly for future testing
+    (err, out) = rgwadmin(ctx, client, [
+            'caps', 'rm',
+            '--uid', admin_user,
+            '--caps', 'users-without-keys=write'
+            ])
+    logging.error(out)
+    logging.error(err)
+    assert not err
+
     # TESTCASE 'suspend-ok','user','suspend','active user','succeeds'
     (ret, out) = rgwadmin_rest(admin_conn, ['user', 'modify'], {'uid' : user1, 'suspended' : True})
     assert ret == 200
@@ -812,4 +873,4 @@ def task(ctx, config):
 
     # TESTCASE 'ratelimit' 'global' 'modify' 'anonymous' 'enabled' 'succeeds'
     (ret, out) = rgwadmin_rest(admin_conn, ['ratelimit', 'modify'], {'ratelimit-scope' : 'bucket', 'global': 'true', 'enabled' : 'true'})
-    assert ret == 200
\ No newline at end of file
+    assert ret == 200
index 200f1c03d2e195bf1335c2581d89422d2ffa5d34..b29e20b3e9e66ccbc39d0892a0f2663fcb812cf8 100644 (file)
@@ -84,10 +84,12 @@ public:
 void RGWOp_User_Info::execute(optional_yield y)
 {
   RGWUserAdminOpState op_state(driver);
+  op_state.set_system(s->system_request);
 
   std::string uid_str, access_key_str;
   bool fetch_stats;
   bool sync_stats;
+  bool dump_keys = true;
 
   RESTArgs::get_string(s, "uid", uid_str, &uid_str);
   RESTArgs::get_string(s, "access-key", access_key_str, &access_key_str);
@@ -111,7 +113,14 @@ void RGWOp_User_Info::execute(optional_yield y)
   op_state.set_fetch_stats(fetch_stats);
   op_state.set_sync_stats(sync_stats);
 
-  op_ret = RGWUserAdminOp_User::info(s, driver, op_state, flusher, y);
+  // dump_keys is false if users-without-keys is 'read' and
+  // the user is not the system user
+  int keys_perm = s->user->get_info().caps.check_cap("users-without-keys", RGW_CAP_READ);
+  if (keys_perm == 0 && !op_state.system) {
+    dump_keys = false;
+  }
+
+  op_ret = RGWUserAdminOp_User::info(s, driver, op_state, flusher, dump_keys, y);
 }
 
 class RGWOp_User_Create : public RGWRESTOp {
index b5569e481c53e04cd584e5ffae4e56550e6b40af..9f568943c11c86b4c96853957199edd979be1f9c 100644 (file)
@@ -125,8 +125,8 @@ static void dump_swift_keys_info(Formatter *f, RGWUserInfo &info)
   f->close_section();
 }
 
-static void dump_user_info(Formatter *f, RGWUserInfo &info,
-                           RGWStorageStats *stats = NULL)
+static void dump_user_info(const DoutPrefixProvider* dpp, Formatter *f, RGWUserInfo &info,
+                           bool dump_keys, RGWStorageStats *stats = NULL)
 {
   f->open_object_section("user_info");
   encode_json("tenant", info.user_id.tenant, f);
@@ -137,8 +137,11 @@ static void dump_user_info(Formatter *f, RGWUserInfo &info,
   encode_json("max_buckets", (int)info.max_buckets, f);
 
   dump_subusers_info(f, info);
-  dump_access_keys_info(f, info);
-  dump_swift_keys_info(f, info);
+
+  if (dump_keys) {
+    dump_access_keys_info(f, info);
+    dump_swift_keys_info(f, info);
+  }
 
   encode_json("caps", info.caps, f);
 
@@ -2098,6 +2101,7 @@ int RGWUserAdminOp_User::list(const DoutPrefixProvider *dpp, rgw::sal::Driver* d
 int RGWUserAdminOp_User::info(const DoutPrefixProvider *dpp,
                              rgw::sal::Driver* driver, RGWUserAdminOpState& op_state,
                              RGWFormatterFlusher& flusher,
+                              bool dump_keys,
                              optional_yield y)
 {
   RGWUserInfo info;
@@ -2140,7 +2144,7 @@ int RGWUserAdminOp_User::info(const DoutPrefixProvider *dpp,
   if (formatter) {
     flusher.start(0);
 
-    dump_user_info(formatter, info, arg_stats);
+    dump_user_info(dpp, formatter, info, dump_keys, arg_stats);
     flusher.flush();
   }
 
@@ -2174,7 +2178,7 @@ int RGWUserAdminOp_User::create(const DoutPrefixProvider *dpp,
   if (formatter) {
     flusher.start(0);
 
-    dump_user_info(formatter, info);
+    dump_user_info(dpp, formatter, info, true);
     flusher.flush();
   }
 
@@ -2207,7 +2211,7 @@ int RGWUserAdminOp_User::modify(const DoutPrefixProvider *dpp,
   if (formatter) {
     flusher.start(0);
 
-    dump_user_info(formatter, info);
+    dump_user_info(dpp, formatter, info, true);
     flusher.flush();
   }
 
index a0cd7ed84fee7b295336c8c0c3957040ef410d1c..91c859feafca512dd7883d7e11b1733da63105f6 100644 (file)
@@ -645,7 +645,7 @@ public:
   static int info(const DoutPrefixProvider *dpp,
                  rgw::sal::Driver* driver,
                   RGWUserAdminOpState& op_state, RGWFormatterFlusher& flusher,
-                 optional_yield y);
+                 bool dump_keys, optional_yield y);
 
   static int create(const DoutPrefixProvider *dpp,
                    rgw::sal::Driver* driver,
index b16d9d97fa8e979330bc6e87bd4028a287e24711..47a37a289fb4b3c5bc43ef501012f07da5eb3002 100644 (file)
@@ -2091,6 +2091,7 @@ bool RGWUserCaps::is_valid_cap_type(const string& tp)
                                     "user-policy",
                                     "amz-cache",
                                     "oidc-provider",
+                                    "users-without-keys",
                                                            "ratelimit"};
 
   for (unsigned int i = 0; i < sizeof(cap_type) / sizeof(char *); ++i) {