#include <list>
+#include "common/ceph_json.h"
#include "rgw_common.h"
#include "rgw_user.h"
#include "rgw_acl_swift.h"
#define SWIFT_PERM_READ RGW_PERM_READ_OBJS
#define SWIFT_PERM_WRITE RGW_PERM_WRITE_OBJS
+/* FIXME: do we really need separate RW? */
+#define SWIFT_PERM_RWRT (SWIFT_PERM_READ | SWIFT_PERM_WRITE)
+#define SWIFT_PERM_ADMIN RGW_PERM_FULL_CONTROL
#define SWIFT_GROUP_ALL_USERS ".r:*"
}
}
+void RGWAccessControlPolicy_SWIFTAcct::add_grants(RGWRados * const store,
+ const list<string>& uids,
+ const int perm)
+{
+ for (const auto uid : uids) {
+ ACLGrant grant;
+ RGWUserInfo grant_user;
+
+ if (uid_is_public(uid)) {
+ grant.set_group(ACL_GROUP_ALL_USERS, perm);
+ acl.add_grant(&grant);
+ } else {
+ rgw_user user(uid);
+
+ if (rgw_get_user_info_by_uid(store, user, grant_user) < 0) {
+ ldout(cct, 10) << "grant user does not exist:" << uid << dendl;
+ /* skipping silently */
+ } else {
+ grant.set_canon(user, grant_user.display_name, perm);
+ acl.add_grant(&grant);
+ }
+ }
+ }
+}
+
+bool RGWAccessControlPolicy_SWIFTAcct::create(RGWRados * const store,
+ const rgw_user& id,
+ const std::string& name,
+ const std::string& acl_str)
+{
+ acl.create_default(id, name);
+ owner.set_id(id);
+ owner.set_name(name);
+
+ JSONParser parser;
+
+ if (!parser.parse(acl_str.c_str(), acl_str.length())) {
+ ldout(cct, 0) << "ERROR: JSONParser::parse returned error=" << dendl;
+ return false;
+ }
+
+ JSONObjIter iter = parser.find_first("admin");
+ if (!iter.end() && (*iter)->is_array()) {
+ list<string> admin;
+ decode_json_obj(admin, *iter);
+ ldout(cct, 0) << "admins: " << admin << dendl;
+
+ add_grants(store, admin, SWIFT_PERM_ADMIN);
+ }
+
+ iter = parser.find_first("read-write");
+ if (!iter.end() && (*iter)->is_array()) {
+ list<string> readwrite;
+ decode_json_obj(readwrite, *iter);
+ ldout(cct, 0) << "read-write: " << readwrite << dendl;
+
+ add_grants(store, readwrite, SWIFT_PERM_RWRT);
+ }
+
+ iter = parser.find_first("read-only");
+ if (!iter.end() && (*iter)->is_array()) {
+ list<string> readonly;
+ decode_json_obj(readonly, *iter);
+ ldout(cct, 0) << "read-only: " << readonly << dendl;
+
+ add_grants(store, readonly, SWIFT_PERM_READ);
+ }
+
+ return true;
+}
+
+void RGWAccessControlPolicy_SWIFTAcct::to_str(std::string& acl_str) const
+{
+ list<string> admin;
+ list<string> readwrite;
+ list<string> readonly;
+
+ /* Parition the grant map into three not-overlapping groups. */
+ for (const auto item : get_acl().get_grant_map()) {
+ const ACLGrant& grant = item.second;
+ const int perm = grant.get_permission().get_permissions();
+
+ rgw_user id;
+ if (!grant.get_id(id)) {
+ if (grant.get_group() != ACL_GROUP_ALL_USERS) {
+ continue;
+ }
+ id = SWIFT_GROUP_ALL_USERS;
+ }
+
+ if (SWIFT_PERM_ADMIN == (perm & SWIFT_PERM_ADMIN)) {
+ admin.insert(admin.end(), id.to_str());
+ } else if (SWIFT_PERM_RWRT == (perm & SWIFT_PERM_RWRT)) {
+ readwrite.insert(readwrite.end(), id.to_str());
+ } else if (SWIFT_PERM_READ == (perm & SWIFT_PERM_READ)) {
+ readonly.insert(readonly.end(), id.to_str());
+ } else {
+ // FIXME: print a warning
+ }
+ }
+
+ /* Serialize the groups. */
+ JSONFormatter formatter;
+
+ formatter.open_object_section("acl");
+ if (!readonly.empty()) {
+ encode_json("read-only", readonly, &formatter);
+ }
+ if (!readwrite.empty()) {
+ encode_json("read-write", readwrite, &formatter);
+ }
+ if (!admin.empty()) {
+ encode_json("admin", admin, &formatter);
+ }
+ formatter.close_section();
+
+ std::ostringstream oss;
+ formatter.flush(oss);
+
+ acl_str = oss.str();
+}
void to_str(string& read, string& write);
};
+class RGWAccessControlPolicy_SWIFTAcct : public RGWAccessControlPolicy
+{
+public:
+ RGWAccessControlPolicy_SWIFTAcct(CephContext * const _cct)
+ : RGWAccessControlPolicy(_cct)
+ {}
+ ~RGWAccessControlPolicy_SWIFTAcct() {}
+
+ void add_grants(RGWRados *store, const list<string>& uids, int perm);
+ bool create(RGWRados *store,
+ const rgw_user& id,
+ const string& name,
+ const string& acl_str);
+ void to_str(string& acl) const;
+};
#endif
* through a well-defined interface. For more details, see rgw_auth.h. */
std::unique_ptr<RGWIdentityApplier> auth_identity;
+ std::unique_ptr<RGWAccessControlPolicy> user_acl;
RGWAccessControlPolicy *bucket_acl;
RGWAccessControlPolicy *object_acl;
return 0;
}
-static int get_bucket_policy_from_attr(CephContext *cct, RGWRados *store, void *ctx,
- RGWBucketInfo& bucket_info, map<string, bufferlist>& bucket_attrs,
- RGWAccessControlPolicy *policy, rgw_obj& obj)
+
+static int get_user_policy_from_attr(CephContext * const cct,
+ RGWRados * const store,
+ map<string, bufferlist>& attrs,
+ RGWAccessControlPolicy& policy /* out */)
+{
+ auto aiter = attrs.find(RGW_ATTR_ACL);
+ if (aiter != attrs.end()) {
+ int ret = decode_policy(cct, aiter->second, &policy);
+ if (ret < 0) {
+ return ret;
+ }
+ } else {
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+static int get_bucket_policy_from_attr(CephContext *cct,
+ RGWRados *store,
+ void *ctx,
+ RGWBucketInfo& bucket_info,
+ map<string, bufferlist>& bucket_attrs,
+ RGWAccessControlPolicy *policy,
+ rgw_obj& obj)
{
map<string, bufferlist>::iterator aiter = bucket_attrs.find(RGW_ATTR_ACL);
}
/**
- * Get the AccessControlPolicy for a bucket or object off of disk.
+ * Get the AccessControlPolicy for an user, bucket or object off of disk.
* s: The req_state to draw information from.
- * only_bucket: If true, reads the bucket ACL rather than the object ACL.
+ * only_bucket: If true, reads the user and bucket ACLs rather than the object ACL.
* Returns: 0 on success, -ERR# otherwise.
*/
int rgw_build_bucket_policies(RGWRados* store, struct req_state* s)
if(s->dialect.compare("s3") == 0) {
s->bucket_acl = new RGWAccessControlPolicy_S3(s->cct);
} else if(s->dialect.compare("swift") == 0) {
+ s->user_acl = std::unique_ptr<RGWAccessControlPolicy>(
+ new RGWAccessControlPolicy_SWIFTAcct(s->cct));
s->bucket_acl = new RGWAccessControlPolicy_SWIFT(s->cct);
} else {
s->bucket_acl = new RGWAccessControlPolicy(s->cct);
}
}
+ struct {
+ rgw_user uid;
+ std::string display_name;
+ } acct_acl_user = {
+ s->user->user_id,
+ s->user->display_name,
+ };
+
if (!s->bucket_name.empty()) {
s->bucket_exists = true;
if (s->bucket_instance_id.empty()) {
if (s->bucket_exists) {
rgw_obj_key no_obj;
ret = read_policy(store, s, s->bucket_info, s->bucket_attrs, s->bucket_acl, s->bucket, no_obj);
+ acct_acl_user = {
+ s->bucket_info.owner,
+ s->bucket_acl->get_owner().get_display_name(),
+ };
} else {
s->bucket_acl->create_default(s->user->user_id, s->user->display_name);
ret = -ERR_NO_SUCH_BUCKET;
}
}
+ /* handle user ACL only for those APIs which support it */
+ if (s->user_acl) {
+ map<string, bufferlist> uattrs;
+
+ ret = rgw_get_user_attrs_by_uid(store, acct_acl_user.uid, uattrs);
+ if (!ret) {
+ ret = get_user_policy_from_attr(s->cct, store, uattrs, *s->user_acl);
+ }
+ if (-ENOENT == ret) {
+ /* In already existing clusters users won't have ACL. In such case
+ * assuming that only account owner has the rights seems to be
+ * reasonable. That allows to have only one verification logic.
+ * NOTE: there is small compatibility kludge for global, empty tenant:
+ * 1. if we try to reach an existing bucket, its owner is considered
+ * as account owner.
+ * 2. otherwise account owner is identity stored in s->user->user_id. */
+ s->user_acl->create_default(acct_acl_user.uid,
+ acct_acl_user.display_name);
+ ret = 0;
+ } else {
+ ldout(s->cct, 0) << "NOTICE: couldn't get user attrs for handling ACL (user_id="
+ << s->user->user_id
+ << ", ret="
+ << ret
+ << ")" << dendl;
+ return ret;
+ }
+ }
+
+
return ret;
}