cerr << " user rm remove user\n";
cerr << " user suspend suspend a user\n";
cerr << " user enable reenable user after suspension\n";
+ cerr << " caps add add user capabilities\n";
+ cerr << " caps rm remove user capabilities\n";
cerr << " subuser create create a new subuser\n" ;
cerr << " subuser modify modify subuser\n";
cerr << " subuser rm remove subuser\n";
cerr << " --skip-zero-entries log show only dumps entries that don't have zero value\n";
cerr << " in one of the numeric field\n";
cerr << " --categories=<list> comma separated list of categories, used in usage show\n";
+ cerr << " --caps=<caps> list of caps (e.g., \"usage=read, write; user=read\"\n";
cerr << " --yes-i-really-mean-it required for certain operations\n";
cerr << "\n";
cerr << "<date> := \"YYYY-MM-DD[ hh:mm:ss]\"\n";
OPT_OBJECT_RM,
OPT_GC_LIST,
OPT_GC_PROCESS,
+ OPT_CAPS_ADD,
+ OPT_CAPS_RM,
};
static uint32_t str_to_perm(const char *str)
strcmp(cmd, "usage") == 0 ||
strcmp(cmd, "object") == 0 ||
strcmp(cmd, "temp") == 0 ||
+ strcmp(cmd, "caps") == 0 ||
strcmp(cmd, "gc") == 0) {
*need_more = true;
return 0;
} else if (strcmp(prev_cmd, "temp") == 0) {
if (strcmp(cmd, "remove") == 0)
return OPT_TEMP_REMOVE;
+ } else if (strcmp(prev_cmd, "caps") == 0) {
+ if (strcmp(cmd, "add") == 0)
+ return OPT_CAPS_ADD;
+ if (strcmp(cmd, "rm") == 0)
+ return OPT_CAPS_RM;
} else if (strcmp(prev_cmd, "pool") == 0) {
if (strcmp(cmd, "add") == 0)
return OPT_POOL_ADD;
}
formatter->close_section();
+ info.caps.dump(formatter);
+
formatter->close_section();
formatter->flush(cout);
cout << std::endl;
int delete_child_objects = false;
int max_buckets = -1;
map<string, bool> categories;
+ string caps;
std::string val;
std::ostringstream errs;
// do nothing
} else if (ceph_argparse_binary_flag(args, i, &yes_i_really_mean_it, NULL, "--yes-i-really-mean-it", (char*)NULL)) {
// do nothing
+ } else if (ceph_argparse_witharg(args, i, &val, "--caps", (char*)NULL)) {
+ caps = val;
} else {
++i;
}
user_modify_op = (opt_cmd == OPT_USER_MODIFY || opt_cmd == OPT_SUBUSER_MODIFY ||
opt_cmd == OPT_SUBUSER_CREATE || opt_cmd == OPT_SUBUSER_RM ||
- opt_cmd == OPT_KEY_CREATE || opt_cmd == OPT_KEY_RM || opt_cmd == OPT_USER_RM);
+ opt_cmd == OPT_KEY_CREATE || opt_cmd == OPT_KEY_RM || opt_cmd == OPT_USER_RM ||
+ opt_cmd == OPT_CAPS_ADD || opt_cmd == OPT_CAPS_RM);
RGWStoreManager store_manager;
store = store_manager.init(g_ceph_context, false);
case OPT_SUBUSER_CREATE:
case OPT_SUBUSER_MODIFY:
case OPT_KEY_CREATE:
+ case OPT_CAPS_ADD:
+ case OPT_CAPS_RM:
if (!user_id.empty())
info.user_id = user_id;
if (max_buckets >= 0)
else
cerr << "access key modification requires both access key and secret key" << std::endl;
return 1;
+ } else if (opt_cmd == OPT_CAPS_ADD) {
+ err = info.caps.add_from_string(caps);
+ if (err < 0) {
+ cerr << "failed to add caps, err=" << cpp_strerror(-err) << std::endl;
+ return 1;
+ }
+ } else if (opt_cmd == OPT_CAPS_RM) {
+ err = info.caps.remove_from_string(caps);
+ if (err < 0) {
+ cerr << "failed to remove caps, err=" << cpp_strerror(-err) << std::endl;
+ return 1;
+ }
}
if (!display_name.empty())
info.display_name = display_name;
#include "common/Clock.h"
#include "common/Formatter.h"
#include "common/perf_counters.h"
+#include "include/str_list.h"
#include "auth/Crypto.h"
#include <sstream>
return true;
}
+
+static struct {
+ const char *type_name;
+ int perm;
+} cap_names[] = { {"*", RGW_CAP_ALL},
+ {"read", RGW_CAP_READ},
+ {"write", RGW_CAP_WRITE},
+ {NULL, 0} };
+
+int RGWUserCaps::parse_cap_perm(const string& str, uint32_t *perm)
+{
+ list<string> strs;
+ get_str_list(str, strs);
+ list<string>::iterator iter;
+ uint32_t v = 0;
+ for (iter = strs.begin(); iter != strs.end(); ++iter) {
+ string& s = *iter;
+ for (int i = 0; cap_names[i].type_name; i++) {
+ if (s.compare(cap_names[i].type_name) == 0)
+ v |= cap_names[i].perm;
+ }
+ }
+
+ *perm = v;
+ return 0;
+}
+
+static void trim_whitespace(const string& src, string& dst)
+{
+ const char *spacestr = " \t\n\r\f\v";
+ int start = src.find_first_not_of(spacestr);
+ if (start < 0)
+ return;
+
+ int end = src.find_last_not_of(spacestr);
+ dst = src.substr(start, end - start + 1);
+}
+
+int RGWUserCaps::get_cap(const string& cap, string& type, uint32_t *pperm)
+{
+ int pos = cap.find('=');
+ if (pos >= 0) {
+ trim_whitespace(cap.substr(0, pos), type);
+ }
+
+ if (type.size() == 0)
+ return -EINVAL;
+
+ string cap_perm;
+ uint32_t perm = 0;
+ if (pos < (int)cap.size() - 1) {
+ cap_perm = cap.substr(pos + 1);
+ int r = parse_cap_perm(cap_perm, &perm);
+ if (r < 0)
+ return r;
+ }
+
+ *pperm = perm;
+
+ return 0;
+}
+
+int RGWUserCaps::add_cap(const string& cap)
+{
+ uint32_t perm;
+ string type;
+
+ int r = get_cap(cap, type, &perm);
+ if (r < 0)
+ return r;
+
+ caps[type] |= perm;
+
+ return 0;
+}
+
+int RGWUserCaps::remove_cap(const string& cap)
+{
+ uint32_t perm;
+ string type;
+
+ int r = get_cap(cap, type, &perm);
+ if (r < 0)
+ return r;
+
+ map<string, uint32_t>::iterator iter = caps.find(type);
+ if (iter == caps.end())
+ return 0;
+
+ uint32_t& old_perm = iter->second;
+ old_perm &= ~perm;
+ if (!old_perm)
+ caps.erase(iter);
+
+ return 0;
+}
+
+int RGWUserCaps::add_from_string(const string& str)
+{
+ int start = 0;
+ int end;
+ do {
+ end = str.find(';', start);
+ if (end < 0)
+ end = str.size();
+
+ int r = add_cap(str.substr(start, end - start));
+ if (r < 0)
+ return r;
+
+ start = end + 1;
+ } while (start < (int)str.size());
+
+ return 0;
+}
+
+int RGWUserCaps::remove_from_string(const string& str)
+{
+ int start = 0;
+ int end;
+ do {
+ end = str.find(';', start);
+ if (end < 0)
+ end = str.size();
+
+ int r = remove_cap(str.substr(start, end - start));
+ if (r < 0)
+ return r;
+
+ start = end + 1;
+ } while (start < (int)str.size());
+
+ return 0;
+}
+
+void RGWUserCaps::dump(Formatter *f) const
+{
+ f->open_array_section("caps");
+ map<string, uint32_t>::const_iterator iter;
+ for (iter = caps.begin(); iter != caps.end(); ++iter)
+ {
+ f->open_object_section("cap");
+ f->dump_string("type", iter->first);
+ uint32_t perm = iter->second;
+ string perm_str;
+ for (int i=0; cap_names[i].type_name; i++) {
+ if ((perm & cap_names[i].perm) == cap_names[i].perm) {
+ if (perm_str.size())
+ perm_str.append(", ");
+
+ perm_str.append(cap_names[i].type_name);
+ perm &= ~cap_names[i].perm;
+ }
+ }
+ if (perm_str.empty())
+ perm_str = "<none>";
+
+ f->dump_string("perm", perm_str);
+ f->close_section();
+ }
+
+ f->close_section();
+}
+
+bool RGWUserCaps::check_cap(const string& cap, uint32_t perm)
+{
+ map<string, uint32_t>::iterator iter = caps.find(cap);
+ if (iter == caps.end())
+ return false;
+
+ return (iter->second & perm) == perm;
+}
+
#define RGW_FORMAT_XML 1
#define RGW_FORMAT_JSON 2
+#define RGW_CAP_READ 0x1
+#define RGW_CAP_WRITE 0x2
+#define RGW_CAP_ALL (RGW_CAP_READ | RGW_CAP_WRITE)
+
#define RGW_REST_SWIFT 0x1
#define RGW_REST_SWIFT_AUTH 0x2
};
WRITE_CLASS_ENCODER(RGWSubUser);
+class RGWUserCaps
+{
+ map<string, uint32_t> caps;
+
+ int get_cap(const string& cap, string& type, uint32_t *perm);
+ int parse_cap_perm(const string& str, uint32_t *perm);
+ int add_cap(const string& cap);
+ int remove_cap(const string& cap);
+public:
+ int add_from_string(const string& str);
+ int remove_from_string(const string& str);
+
+ void encode(bufferlist& bl) const {
+ ENCODE_START(1, 1, bl);
+ ::encode(caps, bl);
+ ENCODE_FINISH(bl);
+ }
+ void decode(bufferlist::iterator& bl) {
+ DECODE_START(1, bl);
+ ::decode(caps, bl);
+ DECODE_FINISH(bl);
+ }
+ bool check_cap(const string& cap, uint32_t perm);
+ void dump(Formatter *f) const;
+};
+WRITE_CLASS_ENCODER(RGWUserCaps);
+
struct RGWUserInfo
{
map<string, RGWSubUser> subusers;
__u8 suspended;
uint32_t max_buckets;
+ RGWUserCaps caps;
RGWUserInfo() : auid(0), suspended(0), max_buckets(RGW_DEFAULT_MAX_BUCKETS) {}
void encode(bufferlist& bl) const {
- ENCODE_START(10, 9, bl);
+ ENCODE_START(11, 9, bl);
::encode(auid, bl);
string access_key;
string secret_key;
::encode(suspended, bl);
::encode(swift_keys, bl);
::encode(max_buckets, bl);
+ ::encode(caps, bl);
ENCODE_FINISH(bl);
}
void decode(bufferlist::iterator& bl) {
- DECODE_START_LEGACY_COMPAT_LEN_32(10, 9, 9, bl);
+ DECODE_START_LEGACY_COMPAT_LEN_32(11, 9, 9, bl);
if (struct_v >= 2) ::decode(auid, bl);
else auid = CEPH_AUTH_UID_DEFAULT;
string access_key;
} else {
max_buckets = RGW_DEFAULT_MAX_BUCKETS;
}
+ if (struct_v >= 11) {
+ ::decode(caps, bl);
+ }
DECODE_FINISH(bl);
}
void dump(Formatter *f) const;
user rm remove user
user suspend suspend a user
user enable reenable user after suspension
+ caps add add user capabilities
+ caps rm remove user capabilities
subuser create create a new subuser
subuser modify modify subuser
subuser rm remove subuser
--skip-zero-entries log show only dumps entries that don't have zero value
in one of the numeric field
--categories=<list> comma separated list of categories, used in usage show
+ --caps=<caps> list of caps (e.g., "usage=read, write; user=read"
--yes-i-really-mean-it required for certain operations
<date> := "YYYY-MM-DD[ hh:mm:ss]"