diff --git a/src/Makefile.am b/src/Makefile.am index fa084e744a3..d26b2a1b981 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -335,6 +335,7 @@ my_libradosgw_src = \ rgw/librgw.cc \ rgw/rgw_acl.cc \ rgw/rgw_acl_s3.cc \ + rgw/rgw_acl_swift.cc \ rgw/rgw_xml.cc \ rgw/rgw_user.cc \ rgw/rgw_tools.cc \ @@ -1426,6 +1427,7 @@ noinst_HEADERS = \ rgw/rgw_access.h\ rgw/rgw_acl.h\ rgw/rgw_acl_s3.h\ + rgw/rgw_acl_swift.h\ rgw/rgw_xml.h\ rgw/rgw_cache.h\ rgw/rgw_cls_api.h\ diff --git a/src/rgw/rgw_access.h b/src/rgw/rgw_access.h index c9d3077a2ff..45f2e8f735f 100644 --- a/src/rgw/rgw_access.h +++ b/src/rgw/rgw_access.h @@ -228,6 +228,9 @@ public: */ virtual int set_attr(void *ctx, rgw_obj& obj, const char *name, bufferlist& bl) = 0; + virtual int set_attrs(void *ctx, rgw_obj& obj, + map& attrs, + map* rmattrs) { return -ENOTSUP; } /** * stat an object */ diff --git a/src/rgw/rgw_acl_s3.cc b/src/rgw/rgw_acl_s3.cc index 98d2ff00d8b..0b7d8aa5dab 100644 --- a/src/rgw/rgw_acl_s3.cc +++ b/src/rgw/rgw_acl_s3.cc @@ -199,8 +199,10 @@ void ACLGrant_S3::to_xml(ostream& out) { ""; switch (type.get_type()) { case ACL_TYPE_CANON_USER: - out << "" << id << "" << - "" << name << ""; + out << "" << id << ""; + if (name.size()) { + out << "" << name << ""; + } break; case ACL_TYPE_EMAIL_USER: out << "" << email << ""; diff --git a/src/rgw/rgw_acl_swift.cc b/src/rgw/rgw_acl_swift.cc new file mode 100644 index 00000000000..e8559d7577b --- /dev/null +++ b/src/rgw/rgw_acl_swift.cc @@ -0,0 +1,75 @@ + +#include + +#include + +#include "rgw_common.h" +#include "rgw_user.h" +#include "rgw_acl_swift.h" + +using namespace std; + +static int parse_list(string& uid_list, vector& uids) +{ + char *s = strdup(uid_list.c_str()); + if (!s) + return -ENOMEM; + + const char *p = strtok(s, " ,"); + while (p) { + if (*p) { + string acl = p; + uids.push_back(acl); + } + p = strtok(NULL, " ,"); + } + free(s); + return 0; +} + +void RGWAccessControlPolicy_SWIFT::add_grants(vector& uids, int perm) +{ + vector::iterator iter; + for (iter = uids.begin(); iter != uids.end(); ++iter ) { + ACLGrant grant; + RGWUserInfo grant_user; + string& uid = *iter; + if (rgw_get_user_info_by_uid(uid, grant_user) < 0) { + dout(10) << "grant user does not exist:" << uid << dendl; + /* skipping silently */ + } else { + grant.set_canon(uid, grant_user.display_name, perm); + acl.add_grant(&grant); + } + } +} + +bool RGWAccessControlPolicy_SWIFT::create(string& id, string& name, string& read_list, string& write_list) +{ + acl.create_default(id, name); + owner.set_id(id); + owner.set_name(name); + + if (read_list.size()) { + vector uids; + int r = parse_list(read_list, uids); + if (r < 0) { + dout(0) << "ERROR: parse_list returned r=" << r << dendl; + return false; + } + + add_grants(uids, RGW_PERM_READ); + } + if (write_list.size()) { + vector uids; + int r = parse_list(write_list, uids); + if (r < 0) { + dout(0) << "ERROR: parse_list returned r=" << r << dendl; + return false; + } + + add_grants(uids, RGW_PERM_WRITE); + } + return true; +} + diff --git a/src/rgw/rgw_acl_swift.h b/src/rgw/rgw_acl_swift.h new file mode 100644 index 00000000000..09dc21b45af --- /dev/null +++ b/src/rgw/rgw_acl_swift.h @@ -0,0 +1,24 @@ +#ifndef CEPH_RGW_ACL_SWIFT_H +#define CEPH_RGW_ACL_SWIFT3_H + +#include +#include +#include +#include +#include + +#include "rgw_acl.h" + +using namespace std; + +class RGWAccessControlPolicy_SWIFT : public RGWAccessControlPolicy +{ +public: + RGWAccessControlPolicy_SWIFT() {} + ~RGWAccessControlPolicy_SWIFT() {} + + void add_grants(vector& uids, int perm); + bool create(string& id, string& name, string& read_list, string& write_list); +}; + +#endif diff --git a/src/rgw/rgw_cache.cc b/src/rgw/rgw_cache.cc index 015bb81f042..a7ed8acd1a7 100644 --- a/src/rgw/rgw_cache.cc +++ b/src/rgw/rgw_cache.cc @@ -64,7 +64,7 @@ void ObjectCache::put(string& name, ObjectCacheInfo& info) if (info.flags & CACHE_FLAG_META) target.meta = info.meta; - else if (!(info.flags & CACHE_FLAG_APPEND_XATTRS)) + else if (!(info.flags & CACHE_FLAG_MODIFY_XATTRS)) target.flags &= ~CACHE_FLAG_META; // non-meta change should reset meta if (info.flags & CACHE_FLAG_XATTRS) { @@ -73,8 +73,12 @@ void ObjectCache::put(string& name, ObjectCacheInfo& info) for (iter = target.xattrs.begin(); iter != target.xattrs.end(); ++iter) { dout(10) << "updating xattr: name=" << iter->first << " bl.length()=" << iter->second.length() << dendl; } - } else if (info.flags & CACHE_FLAG_APPEND_XATTRS) { + } else if (info.flags & CACHE_FLAG_MODIFY_XATTRS) { map::iterator iter; + for (iter = info.rm_xattrs.begin(); iter != info.rm_xattrs.end(); ++iter) { + dout(10) << "removing xattr: name=" << iter->first << dendl; + target.xattrs.erase(iter->first); + } for (iter = info.xattrs.begin(); iter != info.xattrs.end(); ++iter) { dout(10) << "appending xattr: name=" << iter->first << " bl.length()=" << iter->second.length() << dendl; target.xattrs[iter->first] = iter->second; diff --git a/src/rgw/rgw_cache.h b/src/rgw/rgw_cache.h index 3a29fae7a12..d4f943b472b 100644 --- a/src/rgw/rgw_cache.h +++ b/src/rgw/rgw_cache.h @@ -15,7 +15,7 @@ enum { #define CACHE_FLAG_DATA 0x1 #define CACHE_FLAG_XATTRS 0x2 #define CACHE_FLAG_META 0x4 -#define CACHE_FLAG_APPEND_XATTRS 0x8 +#define CACHE_FLAG_MODIFY_XATTRS 0x8 struct ObjectMetaInfo { uint64_t size; @@ -46,18 +46,20 @@ struct ObjectCacheInfo { uint32_t flags; bufferlist data; map xattrs; + map rm_xattrs; ObjectMetaInfo meta; ObjectCacheInfo() : status(0), flags(0) {} void encode(bufferlist& bl) const { - __u8 struct_v = 1; + __u8 struct_v = 2; ::encode(struct_v, bl); ::encode(status, bl); ::encode(flags, bl); ::encode(data, bl); ::encode(xattrs, bl); ::encode(meta, bl); + ::encode(rm_xattrs, bl); } void decode(bufferlist::iterator& bl) { __u8 struct_v; @@ -67,6 +69,8 @@ struct ObjectCacheInfo { ::decode(data, bl); ::decode(xattrs, bl); ::decode(meta, bl); + if (struct_v >= 2) + ::decode(rm_xattrs, bl); } }; WRITE_CLASS_ENCODER(ObjectCacheInfo) @@ -175,6 +179,9 @@ public: RGWCache() {} int set_attr(void *ctx, rgw_obj& obj, const char *name, bufferlist& bl); + int set_attrs(void *ctx, rgw_obj& obj, + map& attrs, + map* rmattrs); int put_obj_meta(void *ctx, rgw_obj& obj, uint64_t size, time_t *mtime, map& attrs, RGWObjCategory category, bool exclusive, map* rmattrs, const bufferlist *data); @@ -262,7 +269,7 @@ int RGWCache::set_attr(void *ctx, rgw_obj& obj, const char *attr_name, buffer cacheable = true; info.xattrs[attr_name] = bl; info.status = 0; - info.flags = CACHE_FLAG_APPEND_XATTRS; + info.flags = CACHE_FLAG_MODIFY_XATTRS; } int ret = T::set_attr(ctx, obj, attr_name, bl); if (cacheable) { @@ -280,6 +287,40 @@ int RGWCache::set_attr(void *ctx, rgw_obj& obj, const char *attr_name, buffer return ret; } +template +int RGWCache::set_attrs(void *ctx, rgw_obj& obj, + map& attrs, + map* rmattrs) +{ + rgw_bucket bucket; + string oid; + normalize_bucket_and_obj(obj.bucket, obj.object, bucket, oid); + ObjectCacheInfo info; + bool cacheable = false; + if (bucket.name[0] == '.') { + cacheable = true; + info.xattrs = attrs; + if (rmattrs) + info.rm_xattrs = *rmattrs; + info.status = 0; + info.flags = CACHE_FLAG_MODIFY_XATTRS; + } + int ret = T::set_attrs(ctx, obj, attrs, rmattrs); + if (cacheable) { + string name = normal_name(bucket, oid); + if (ret >= 0) { + cache.put(name, info); + int r = distribute(obj, info, UPDATE_OBJ); + if (r < 0) + dout(0) << "ERROR: failed to distribute cache for " << obj << dendl; + } else { + cache.remove(name); + } + } + + return ret; +} + template int RGWCache::put_obj_meta(void *ctx, rgw_obj& obj, uint64_t size, time_t *mtime, map& attrs, RGWObjCategory category, bool exclusive, diff --git a/src/rgw/rgw_op.cc b/src/rgw/rgw_op.cc index ab65c82cdab..df4779d537e 100644 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@ -137,7 +137,7 @@ static void format_xattr(std::string &xattr) * attrs: will be filled up with attrs mapped as * */ -static void get_request_metadata(struct req_state *s, map& attrs) +void rgw_get_request_metadata(struct req_state *s, map& attrs) { map::iterator iter; for (iter = s->x_meta_map.begin(); iter != s->x_meta_map.end(); ++iter) { @@ -980,7 +980,7 @@ void RGWPutObj::execute() attrs[RGW_ATTR_CONTENT_TYPE] = bl; } - get_request_metadata(s, attrs); + rgw_get_request_metadata(s, attrs); ret = processor->complete(etag, attrs); done: @@ -991,7 +991,7 @@ done: return; } -int RGWPutObjMetadata::verify_permission() +int RGWPutMetadata::verify_permission() { if (!verify_object_permission(s, RGW_PERM_WRITE)) return -EACCES; @@ -999,24 +999,26 @@ int RGWPutObjMetadata::verify_permission() return 0; } -void RGWPutObjMetadata::execute() +void RGWPutMetadata::execute() { - ret = -EINVAL; - const char *meta_prefix = RGW_ATTR_META_PREFIX; int meta_prefix_len = sizeof(RGW_ATTR_META_PREFIX) - 1; map attrs, orig_attrs, rmattrs; map::iterator iter; - get_request_metadata(s, attrs); + bufferlist bl; rgw_obj obj(s->bucket, s->object_str); rgwstore->set_atomic(s->obj_ctx, obj); - uint64_t obj_size; + ret = get_params(); + if (ret < 0) + goto done; + + rgw_get_request_metadata(s, attrs); /* check if obj exists, read orig attrs */ - ret = get_obj_attrs(s, obj, orig_attrs, &obj_size); + ret = get_obj_attrs(s, obj, orig_attrs, NULL); if (ret < 0) goto done; @@ -1030,7 +1032,11 @@ void RGWPutObjMetadata::execute() } } - ret = rgwstore->put_obj_meta(s->obj_ctx, obj, obj_size, NULL, attrs, RGW_OBJ_CATEGORY_MAIN, false, &rmattrs, NULL); + if (has_policy) { + policy.encode(bl); + attrs[RGW_ATTR_ACL] = bl; + } + ret = rgwstore->set_attrs(s->obj_ctx, obj, attrs, &rmattrs); done: send_response(); @@ -1159,7 +1165,7 @@ int RGWCopyObj::init_common() dest_policy.encode(aclbl); attrs[RGW_ATTR_ACL] = aclbl; - get_request_metadata(s, attrs); + rgw_get_request_metadata(s, attrs); return 0; } @@ -1341,7 +1347,7 @@ void RGWInitMultipart::execute() attrs[RGW_ATTR_CONTENT_TYPE] = bl; } - get_request_metadata(s, attrs); + rgw_get_request_metadata(s, attrs); do { char buf[33]; diff --git a/src/rgw/rgw_op.h b/src/rgw/rgw_op.h index b24698b31a8..47e27f5107e 100644 --- a/src/rgw/rgw_op.h +++ b/src/rgw/rgw_op.h @@ -21,6 +21,8 @@ using namespace std; struct req_state; class RGWHandler; +void rgw_get_request_metadata(struct req_state *s, map& attrs); + /** * Provide the base class for all ops. */ @@ -306,15 +308,19 @@ public: virtual const char *name() { return "put_obj"; } }; -class RGWPutObjMetadata : public RGWOp { +class RGWPutMetadata : public RGWOp { protected: int ret; + map attrs; + bool has_policy; + RGWAccessControlPolicy policy; public: - RGWPutObjMetadata() {} + RGWPutMetadata() {} virtual void init(struct req_state *s, RGWHandler *h) { RGWOp::init(s, h); + has_policy = false; ret = 0; } int verify_permission(); diff --git a/src/rgw/rgw_rados.cc b/src/rgw/rgw_rados.cc index 3e15c156e1f..42739fb098f 100644 --- a/src/rgw/rgw_rados.cc +++ b/src/rgw/rgw_rados.cc @@ -1307,6 +1307,73 @@ int RGWRados::set_attr(void *ctx, rgw_obj& obj, const char *name, bufferlist& bl return 0; } +int RGWRados::set_attrs(void *ctx, rgw_obj& obj, + map& attrs, + map* rmattrs) +{ + rgw_bucket bucket; + std::string oid, key; + get_obj_bucket_and_oid_key(obj, bucket, oid, key); + librados::IoCtx io_ctx; + string actual_obj = oid; + RGWRadosCtx *rctx = (RGWRadosCtx *)ctx; + rgw_bucket actual_bucket = bucket; + + if (actual_obj.size() == 0) { + actual_obj = bucket.name; + actual_bucket = rgw_root_bucket; + } + + int r = open_bucket_ctx(actual_bucket, io_ctx); + if (r < 0) + return r; + + io_ctx.locator_set_key(key); + + ObjectWriteOperation op; + RGWObjState *state = NULL; + + r = append_atomic_test(rctx, obj, io_ctx, actual_obj, op, &state); + if (r < 0) + return r; + + map::iterator iter; + if (rmattrs) { + for (iter = rmattrs->begin(); iter != rmattrs->end(); ++iter) { + const string& name = iter->first; + op.rmxattr(name.c_str()); + } + } + + for (iter = attrs.begin(); iter != attrs.end(); ++iter) { + const string& name = iter->first; + bufferlist& bl = iter->second; + + if (!bl.length()) + continue; + + op.setxattr(name.c_str(), bl); + } + + if (!op.size()) + return 0; + + r = io_ctx.operate(actual_obj, &op); + + if (r == -ECANCELED) { + /* a race! object was replaced, we need to set attr on the original obj */ + dout(0) << "NOTICE: RGWRados::set_obj_attrs: raced with another process, going to the shadow obj instead" << dendl; + string loc = obj.loc(); + rgw_obj shadow(obj.bucket, state->shadow_obj, loc, shadow_ns); + r = set_attrs(NULL, shadow, attrs, rmattrs); + } + + if (r < 0) + return r; + + return 0; +} + /** * Get data about an object out of RADOS and into memory. * bucket: name of the bucket the object is in. diff --git a/src/rgw/rgw_rados.h b/src/rgw/rgw_rados.h index 2ee053f0971..9c2084d4eb3 100644 --- a/src/rgw/rgw_rados.h +++ b/src/rgw/rgw_rados.h @@ -264,6 +264,10 @@ public: /** Set an attr on an object. */ virtual int set_attr(void *ctx, rgw_obj& obj, const char *name, bufferlist& bl); + virtual int set_attrs(void *ctx, rgw_obj& obj, + map& attrs, + map* rmattrs); + /** Get data about an object out of RADOS and into memory. */ virtual int prepare_get_obj(void *ctx, rgw_obj& obj, off_t *ofs, off_t *end, diff --git a/src/rgw/rgw_rest.cc b/src/rgw/rgw_rest.cc index bb4afc74444..14813282ecc 100644 --- a/src/rgw/rgw_rest.cc +++ b/src/rgw/rgw_rest.cc @@ -602,6 +602,7 @@ struct str_len meta_prefixes[] = { STR_LEN_ENTRY("HTTP_X_AMZ"), STR_LEN_ENTRY("HTTP_X_GOOG"), STR_LEN_ENTRY("HTTP_X_DHO"), STR_LEN_ENTRY("HTTP_X_OBJECT"), + STR_LEN_ENTRY("HTTP_X_CONTAINER"), {NULL, 0} }; static int init_auth_info(struct req_state *s) diff --git a/src/rgw/rgw_rest.h b/src/rgw/rgw_rest.h index 5ce9bd958d1..228267d86be 100644 --- a/src/rgw/rgw_rest.h +++ b/src/rgw/rgw_rest.h @@ -67,11 +67,11 @@ public: int get_data(bufferlist& bl); }; -class RGWPutObjMetadata_REST : public RGWPutObjMetadata +class RGWPutMetadata_REST : public RGWPutMetadata { public: - RGWPutObjMetadata_REST() {} - ~RGWPutObjMetadata_REST() {} + RGWPutMetadata_REST() {} + ~RGWPutMetadata_REST() {} }; class RGWDeleteObj_REST : public RGWDeleteObj { diff --git a/src/rgw/rgw_rest_swift.cc b/src/rgw/rgw_rest_swift.cc index 9c39a241330..f7562553261 100644 --- a/src/rgw/rgw_rest_swift.cc +++ b/src/rgw/rgw_rest_swift.cc @@ -2,6 +2,7 @@ #include "common/Formatter.h" #include "rgw_swift.h" #include "rgw_rest_swift.h" +#include "rgw_acl_swift.h" #include @@ -309,14 +310,38 @@ void RGWPutObj_REST_SWIFT::send_response() flush_formatter_to_req_state(s, s->formatter); } -int RGWPutObjMetadata_REST_SWIFT::get_params() +int RGWPutMetadata_REST_SWIFT::get_params() { if (s->has_bad_meta) return -EINVAL; + + if (!s->object) { + string read_list, write_list; + + const char *read_attr = s->env->get("HTTP_X_CONTAINER_READ"); + if (read_attr) { + read_list = read_attr; + } + const char *write_attr = s->env->get("HTTP_X_CONTAINER_WRITE"); + if (write_attr) { + write_list = write_attr; + } + + if (read_attr || write_attr) { + RGWAccessControlPolicy_SWIFT swift_policy; + int r = swift_policy.create(s->user.user_id, s->user.display_name, read_list, write_list); + if (r < 0) + return r; + + policy = swift_policy; + has_policy = true; + } + } + return 0; } -void RGWPutObjMetadata_REST_SWIFT::send_response() +void RGWPutMetadata_REST_SWIFT::send_response() { if (!ret) ret = STATUS_ACCEPTED; @@ -415,7 +440,7 @@ int RGWGetObj_REST_SWIFT::send_response(void *handle) const char *name = iter->first.c_str(); if (strncmp(name, RGW_ATTR_META_PREFIX, sizeof(RGW_ATTR_META_PREFIX)-1) == 0) { name += sizeof(RGW_ATTR_META_PREFIX) - 1; - CGI_PRINTF(s,"X-Object-Meta-%s: %s\r\n", name, iter->second.c_str()); + CGI_PRINTF(s,"X-%s-Meta-%s: %s\r\n", (s->object ? "Object" : "Container"), name, iter->second.c_str()); } else if (!content_type && strcmp(name, RGW_ATTR_CONTENT_TYPE) == 0) { content_type = iter->second.c_str(); } @@ -506,10 +531,7 @@ RGWOp *RGWHandler_REST_SWIFT::get_delete_op() RGWOp *RGWHandler_REST_SWIFT::get_post_op() { - if (s->object) - return new RGWPutObjMetadata_REST_SWIFT; - - return NULL; + return new RGWPutMetadata_REST_SWIFT; } RGWOp *RGWHandler_REST_SWIFT::get_copy_op() diff --git a/src/rgw/rgw_rest_swift.h b/src/rgw/rgw_rest_swift.h index cabd1250a4e..0870e617e9a 100644 --- a/src/rgw/rgw_rest_swift.h +++ b/src/rgw/rgw_rest_swift.h @@ -83,10 +83,10 @@ public: void send_response(); }; -class RGWPutObjMetadata_REST_SWIFT : public RGWPutObjMetadata_REST { +class RGWPutMetadata_REST_SWIFT : public RGWPutMetadata_REST { public: - RGWPutObjMetadata_REST_SWIFT() {} - ~RGWPutObjMetadata_REST_SWIFT() {} + RGWPutMetadata_REST_SWIFT() {} + ~RGWPutMetadata_REST_SWIFT() {} int get_params(); void send_response();