From: Yehuda Sadeh Date: Fri, 19 Feb 2016 22:34:13 +0000 (-0800) Subject: Merge remote-tracking branch 'jmunhoz/wip-aws4' into wip-aws4 X-Git-Tag: v10.1.0~351^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=552715995ce15aec5ffcdb562e9ebe799c0b9497;p=ceph.git Merge remote-tracking branch 'jmunhoz/wip-aws4' into wip-aws4 Signed-off-by: Yehuda Sadeh Conflicts: src/rgw/rgw_auth_s3.h src/rgw/rgw_client_io.cc src/rgw/rgw_client_io.h src/rgw/rgw_common.h src/rgw/rgw_main.cc src/rgw/rgw_op.cc src/rgw/rgw_op.h src/rgw/rgw_rest.cc src/rgw/rgw_rest_metadata.cc src/rgw/rgw_rest_s3.cc --- 552715995ce15aec5ffcdb562e9ebe799c0b9497 diff --cc src/rgw/rgw_auth_s3.cc index b372630cb3e2,82ea8763f2d9..9525a71d52a9 --- a/src/rgw/rgw_auth_s3.cc +++ b/src/rgw/rgw_auth_s3.cc @@@ -2,7 -2,9 +2,10 @@@ // vim: ts=8 sw=2 smarttab #include "common/armor.h" + #include "common/utf8.h" #include "rgw_common.h" + #include "rgw_client_io.h" ++#include "rgw_rest.h" #define dout_subsys ceph_subsys_rgw @@@ -214,3 -221,193 +222,193 @@@ bool rgw_create_s3_canonical_header(req return true; } + + /* + * assemble canonical request for signature version 4 + */ + void rgw_assemble_s3_v4_canonical_request(const char *method, const char *canonical_uri, const char *canonical_qs, + const char *canonical_hdrs, const char *signed_hdrs, const char *request_payload_hash, + string& dest_str) + { + string dest; + + if (method) + dest = method; + dest.append("\n"); + + if (canonical_uri) { + dest.append(canonical_uri); + } + dest.append("\n"); + + if (canonical_qs) { + dest.append(canonical_qs); + } + dest.append("\n"); + + if (canonical_hdrs) + dest.append(canonical_hdrs); + dest.append("\n"); + + if (signed_hdrs) + dest.append(signed_hdrs); + dest.append("\n"); + + if (request_payload_hash) + dest.append(request_payload_hash); + + dest_str = dest; + } + + /* + * create canonical request for signature version 4 + */ + void rgw_create_s3_v4_canonical_request(struct req_state *s, const string& canonical_uri, const string& canonical_qs, + const string& canonical_hdrs, const string& signed_hdrs, const string& request_payload, + bool unsigned_payload, string& canonical_req, string& canonical_req_hash) + { + string request_payload_hash; + + if (unsigned_payload) { + request_payload_hash = "UNSIGNED-PAYLOAD"; + } else { + if (s->aws4_auth_needs_complete) { - request_payload_hash = s->cio->grab_aws4_sha256_hash(); ++ request_payload_hash = STREAM_IO(s)->grab_aws4_sha256_hash(); + } else { + rgw_hash_s3_string_sha256(request_payload.c_str(), request_payload.size(), request_payload_hash); + } + } + + s->aws4_auth->payload_hash = request_payload_hash; + + ldout(s->cct, 10) << "payload request hash = " << request_payload_hash << dendl; + + rgw_assemble_s3_v4_canonical_request(s->info.method, canonical_uri.c_str(), + canonical_qs.c_str(), canonical_hdrs.c_str(), signed_hdrs.c_str(), + request_payload_hash.c_str(), canonical_req); + + rgw_hash_s3_string_sha256(canonical_req.c_str(), canonical_req.size(), canonical_req_hash); + + ldout(s->cct, 10) << "canonical request = " << canonical_req << dendl; + ldout(s->cct, 10) << "canonical request hash = " << canonical_req_hash << dendl; + } + + /* + * assemble string to sign for signature version 4 + */ + void rgw_assemble_s3_v4_string_to_sign(const char *algorithm, const char *request_date, + const char *credential_scope, const char *hashed_qr, string& dest_str) + { + string dest; + + if (algorithm) + dest = algorithm; + dest.append("\n"); + + if (request_date) + dest.append(request_date); + dest.append("\n"); + + if (credential_scope) + dest.append(credential_scope); + dest.append("\n"); + + if (hashed_qr) + dest.append(hashed_qr); + + dest_str = dest; + } + + /* + * create string to sign for signature version 4 + */ + void rgw_create_s3_v4_string_to_sign(CephContext *cct, const string& algorithm, const string& request_date, + const string& credential_scope, const string& hashed_qr, + string& string_to_sign) { + + rgw_assemble_s3_v4_string_to_sign(algorithm.c_str(), request_date.c_str(), + credential_scope.c_str(), hashed_qr.c_str(), string_to_sign); + + ldout(cct, 10) << "string to sign = " << string_to_sign << dendl; + } + + /* + * calculate the AWS signature version 4 + */ + int rgw_calculate_s3_v4_aws_signature(struct req_state *s, + const string& access_key_id, const string &date, const string& region, + const string& service, const string& string_to_sign, string& signature) { + - map::iterator iter = s->user.access_keys.find(access_key_id); - if (iter == s->user.access_keys.end()) { ++ map::iterator iter = s->user->access_keys.find(access_key_id); ++ if (iter == s->user->access_keys.end()) { + ldout(s->cct, 10) << "ERROR: access key not encoded in user info" << dendl; + return -EPERM; + } + + RGWAccessKey& k = iter->second; + + string secret_key = "AWS4" + k.key; + + char secret_k[secret_key.size() * MAX_UTF8_SZ]; + + size_t n = 0; + + for (size_t i = 0; i < secret_key.size(); i++) { + n += encode_utf8(secret_key[i], (unsigned char *) (secret_k + n)); + } + + string secret_key_utf8_k(secret_k, n); + + /* date */ + + char date_k[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE]; + calc_hmac_sha256(secret_key_utf8_k.c_str(), secret_key_utf8_k.size(), + date.c_str(), date.size(), date_k); + + char aux[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE * 2 + 1]; + buf_to_hex((unsigned char *) date_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, aux); + + ldout(s->cct, 10) << "date_k = " << string(aux) << dendl; + + /* region */ + + char region_k[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE]; + calc_hmac_sha256(date_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, region.c_str(), region.size(), region_k); + + buf_to_hex((unsigned char *) region_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, aux); + + ldout(s->cct, 10) << "region_k = " << string(aux) << dendl; + + /* service */ + + char service_k[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE]; + calc_hmac_sha256(region_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, service.c_str(), service.size(), service_k); + + buf_to_hex((unsigned char *) service_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, aux); + + ldout(s->cct, 10) << "service_k = " << string(aux) << dendl; + + /* aws4_request */ + + char signing_k[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE]; + calc_hmac_sha256(service_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, "aws4_request", 12, signing_k); + + buf_to_hex((unsigned char *) signing_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, aux); + + ldout(s->cct, 10) << "signing_k = " << string(aux) << dendl; + + /* new signature */ + + char signature_k[CEPH_CRYPTO_HMACSHA256_DIGESTSIZE]; + calc_hmac_sha256(signing_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, string_to_sign.c_str(), string_to_sign.size(), signature_k); + + buf_to_hex((unsigned char *) signature_k, CEPH_CRYPTO_HMACSHA256_DIGESTSIZE, aux); + + ldout(s->cct, 10) << "signature_k = " << string(aux) << dendl; + + signature = string(aux); + + ldout(s->cct, 10) << "new signature = " << signature << dendl; + + return 0; + } diff --cc src/rgw/rgw_auth_s3.h index 840b2697a353,b5b49429475a..4e8dd1ca5c8b --- a/src/rgw/rgw_auth_s3.h +++ b/src/rgw/rgw_auth_s3.h @@@ -7,16 -7,16 +7,31 @@@ #include "rgw_common.h" -void rgw_create_s3_canonical_header(const char *method, const char *content_md5, const char *content_type, const char *date, - map& meta_map, const char *request_uri, map& sub_resources, - string& dest_str); -bool rgw_create_s3_canonical_header(req_info& info, utime_t *header_time, string& dest, bool qsr); +void rgw_create_s3_canonical_header(const char *method, + const char *content_md5, + const char *content_type, const char *date, + map& meta_map, + const char *request_uri, + map& sub_resources, + string& dest_str); +bool rgw_create_s3_canonical_header(req_info& info, utime_t *header_time, + string& dest, bool qsr); +int rgw_get_s3_header_digest(const string& auth_hdr, const string& key, + string& dest); + int rgw_get_s3_header_digest(const string& auth_hdr, const string& key, string& dest); ++ + void rgw_hash_s3_string_sha256(const char *data, int len, string& dest); -void rgw_create_s3_v4_canonical_request(struct req_state *s, const string& canonical_uri, const string& canonical_qs, - const string& canonical_hdrs, const string& signed_hdrs, const string& request_payload, - bool unsigned_payload, string& canonical_req, string& canonical_req_hash); -void rgw_create_s3_v4_string_to_sign(CephContext *cct, const string& algorithm, const string& request_date, const string& credential_scope, const string& hashed_qr, string& string_to_sign); -int rgw_calculate_s3_v4_aws_signature(struct req_state *s, const string& access_key_id, const string &date, const string& region, const string& service, const string& string_to_sign, string& signature); ++void rgw_create_s3_v4_canonical_request(struct req_state *s, const string& canonical_uri, ++ const string& canonical_qs, const string& canonical_hdrs, ++ const string& signed_hdrs, const string& request_payload, ++ bool unsigned_payload, ++ string& canonical_req, string& canonical_req_hash); ++void rgw_create_s3_v4_string_to_sign(CephContext *cct, const string& algorithm, ++ const string& request_date, const string& credential_scope, ++ const string& hashed_qr, string& string_to_sign); ++int rgw_calculate_s3_v4_aws_signature(struct req_state *s, const string& access_key_id, ++ const string &date, const string& region, ++ const string& service, const string& string_to_sign, ++ string& signature); #endif diff --cc src/rgw/rgw_client_io.cc index 26d89259f0ba,d13dce877dcf..b326a61b7faf --- a/src/rgw/rgw_client_io.cc +++ b/src/rgw/rgw_client_io.cc @@@ -69,7 -70,8 +69,7 @@@ int RGWStreamIO::write(const char *buf return 0; } - int RGWStreamIO::read(char *buf, int max, int *actual) - -int RGWClientIO::read(char *buf, int max, int *actual, bool hash /* = false */) ++int RGWStreamIO::read(char *buf, int max, int *actual, bool hash /* = false */) { int ret = read_data(buf, max); if (ret < 0) @@@ -79,5 -81,18 +79,17 @@@ bytes_received += *actual; + if (hash) { + if (!sha256_hash) { + sha256_hash = calc_hash_sha256_open_stream(); + } + calc_hash_sha256_update_stream(sha256_hash, buf, *actual); + } + return 0; } + - -string RGWClientIO::grab_aws4_sha256_hash() ++string RGWStreamIO::grab_aws4_sha256_hash() + { + return calc_hash_sha256_close_stream(&sha256_hash); + } diff --cc src/rgw/rgw_client_io.h index a25b193efa5a,d8dc803a0752..09cf332b1eca --- a/src/rgw/rgw_client_io.h +++ b/src/rgw/rgw_client_io.h @@@ -20,38 -23,15 +20,40 @@@ protected virtual void init_env(CephContext *cct) = 0; +public: + virtual ~RGWClientIO() {} + RGWClientIO() : _account(false) {} + + void init(CephContext *cct); + RGWEnv& get_env() { return env; } + + bool account() { return _account; } + void set_account(bool _accnt) { + _account = _accnt; + } + + virtual int complete_request() = 0; /* XXX signature likely changing */ + + virtual uint64_t get_bytes_sent() { return 0; } + virtual uint64_t get_bytes_received() { return 0; } +}; /* RGWClient IO */ + +/* HTTP IO */ +class RGWStreamIO : public RGWClientIO { + + size_t bytes_sent; + size_t bytes_received; + ++ SHA256 *sha256_hash; ++ +protected: virtual int write_data(const char *buf, int len) = 0; virtual int read_data(char *buf, int max) = 0; public: - virtual ~RGWClientIO() {} - RGWClientIO() : account(false), bytes_sent(0), bytes_received(0), sha256_hash(NULL) {} + virtual ~RGWStreamIO() {} - RGWStreamIO() : bytes_sent(0), bytes_received(0) {} ++ RGWStreamIO() : bytes_sent(0), bytes_received(0), sha256_hash(nullptr) {} - void init(CephContext *cct); int print(const char *format, ...); int write(const char *buf, int len); virtual void flush() = 0; diff --cc src/rgw/rgw_common.h index 3cc3c4b64c97,f94c0a485ee2..2ea635a205e1 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@@ -378,6 -372,48 +379,49 @@@ enum http_op OP_UNKNOWN, }; + enum RGWOpType { + RGW_OP_UNKNOWN = 0, + RGW_OP_GET_OBJ, + RGW_OP_LIST_BUCKETS, + RGW_OP_STAT_ACCOUNT, + RGW_OP_LIST_BUCKET, + RGW_OP_GET_BUCKET_LOGGING, + RGW_OP_GET_BUCKET_VERSIONING, + RGW_OP_SET_BUCKET_VERSIONING, + RGW_OP_GET_BUCKET_WEBSITE, + RGW_OP_SET_BUCKET_WEBSITE, + RGW_OP_STAT_BUCKET, + RGW_OP_CREATE_BUCKET, + RGW_OP_DELETE_BUCKET, + RGW_OP_PUT_OBJ, ++ RGW_OP_STAT_OBJ, + RGW_OP_POST_OBJ, + RGW_OP_PUT_METADATA_ACCOUNT, + RGW_OP_PUT_METADATA_BUCKET, + RGW_OP_PUT_METADATA_OBJECT, + RGW_OP_SET_TEMPURL, + RGW_OP_DELETE_OBJ, + RGW_OP_COPY_OBJ, + RGW_OP_GET_ACLS, + RGW_OP_PUT_ACLS, + RGW_OP_GET_CORS, + RGW_OP_PUT_CORS, + RGW_OP_DELETE_CORS, + RGW_OP_OPTIONS_CORS, + RGW_OP_GET_REQUEST_PAYMENT, + RGW_OP_SET_REQUEST_PAYMENT, + RGW_OP_INIT_MULTIPART, + RGW_OP_COMPLETE_MULTIPART, + RGW_OP_ABORT_MULTIPART, + RGW_OP_LIST_MULTIPART, + RGW_OP_LIST_BUCKET_MULTIPARTS, + RGW_OP_DELETE_MULTI_OBJ, + RGW_OP_BULK_DELETE, + + /* rgw specific */ + RGW_OP_ADMIN_SET_METADATA + }; + class RGWAccessControlPolicy; class JSONObj; @@@ -1087,89 -1127,92 +1147,94 @@@ struct req_init_state string src_bucket; }; +/* XXX why don't RGWRequest (or descendants) hold this state? */ +class RGWRequest; + /** Store all the state necessary to complete and respond to an HTTP request*/ struct req_state { - CephContext *cct; - RGWClientIO *cio; - http_op op; - RGWOpType op_type; - bool content_started; - int format; - ceph::Formatter *formatter; - string decoded_uri; - string relative_uri; - const char *length; - int64_t content_length; - map generic_attrs; - struct rgw_err err; - bool expect_cont; - bool header_ended; - uint64_t obj_size; - bool enable_ops_log; - bool enable_usage_log; - uint8_t defer_to_bucket_acls; - uint32_t perm_mask; - utime_t header_time; - - /* Set once when url_bucket is parsed and not violated thereafter. */ - string bucket_tenant; - string bucket_name; - - rgw_bucket bucket; - rgw_obj_key object; - string src_tenant_name; - string src_bucket_name; - rgw_obj_key src_object; - ACLOwner bucket_owner; - ACLOwner owner; - - string region_endpoint; - string bucket_instance_id; - - string redirect; + CephContext *cct; + RGWClientIO *cio; + RGWRequest *req; /// XXX: re-remove?? + http_op op; ++ RGWOpType op_type; + bool content_started; + int format; + ceph::Formatter *formatter; + string decoded_uri; + string relative_uri; + const char *length; + int64_t content_length; + map generic_attrs; + struct rgw_err err; + bool expect_cont; + bool header_ended; + uint64_t obj_size; + bool enable_ops_log; + bool enable_usage_log; + uint8_t defer_to_bucket_acls; + uint32_t perm_mask; + utime_t header_time; - RGWBucketInfo bucket_info; - map bucket_attrs; - bool bucket_exists; + /* Set once when url_bucket is parsed and not violated thereafter. */ + string bucket_tenant; + string bucket_name; - bool has_bad_meta; + rgw_bucket bucket; + rgw_obj_key object; + string src_tenant_name; + string src_bucket_name; + rgw_obj_key src_object; + ACLOwner bucket_owner; + ACLOwner owner; - RGWUserInfo user; - RGWAccessControlPolicy *bucket_acl; - RGWAccessControlPolicy *object_acl; + string zonegroup_name; + string zonegroup_endpoint; + string bucket_instance_id; + int bucket_instance_shard_id; - bool system_request; + string redirect; - string canned_acl; - bool has_acl_header; - const char *http_auth; - bool local_source; /* source is local */ + RGWBucketInfo bucket_info; + map bucket_attrs; + bool bucket_exists; - int prot_flags; + bool has_bad_meta; - const char *os_auth_token; - string swift_user; - string swift_groups; + RGWUserInfo *user; - /* aws4 auth support */ - bool aws4_auth_needs_complete; + RGWAccessControlPolicy *bucket_acl; + RGWAccessControlPolicy *object_acl; - rgw_aws4_auth *aws4_auth; + bool system_request; - utime_t time; ++ /* aws4 auth support */ ++ bool aws4_auth_needs_complete; ++ rgw_aws4_auth *aws4_auth; + - void *obj_ctx; + string canned_acl; + bool has_acl_header; + const char *http_auth; + bool local_source; /* source is local */ - string dialect; + int prot_flags; - string req_id; + const char *os_auth_token; + string swift_user; + string swift_groups; - string trans_id; + string host_id; - string host_id; + req_info info; + req_init_state init_state; - req_info info; - req_init_state init_state; + utime_t time; + void *obj_ctx; + string dialect; + string req_id; + string trans_id; - req_state(CephContext *_cct, class RGWEnv *e); - ~req_state(); + req_state(CephContext* _cct, RGWEnv* e, RGWUserInfo* u); + ~req_state(); }; /** Store basic data on an object */ diff --cc src/rgw/rgw_op.cc index f3c95ea976c9,4ff45120076c..b4171217c887 --- a/src/rgw/rgw_op.cc +++ b/src/rgw/rgw_op.cc @@@ -25,7 -25,7 +25,8 @@@ #include "rgw_multi_del.h" #include "rgw_cors.h" #include "rgw_cors_s3.h" +#include "rgw_rest_conn.h" + #include "rgw_rest_s3.h" #include "rgw_client_io.h" diff --cc src/rgw/rgw_op.h index c977bf2e9673,6b69c01ea39f..895c2b3991e4 --- a/src/rgw/rgw_op.h +++ b/src/rgw/rgw_op.h @@@ -93,11 -45,12 +53,13 @@@ protected RGWQuotaInfo user_quota; int op_ret; + int do_aws4_auth_completion(); + virtual int init_quota(); public: -RGWOp() : s(NULL), dialect_handler(NULL), store(NULL), cors_exist(false), - op_ret(0) {} +RGWOp() : s(nullptr), dialect_handler(nullptr), store(nullptr), + cors_exist(false), op_ret(0) {} + virtual ~RGWOp() {} int get_ret() const { return op_ret; } diff --cc src/rgw/rgw_process.cc index 5095fe77846a,000000000000..6a92c49ce673 mode 100644,000000..100644 --- a/src/rgw/rgw_process.cc +++ b/src/rgw/rgw_process.cc @@@ -1,204 -1,0 +1,206 @@@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "common/errno.h" +#include "common/Throttle.h" +#include "common/WorkQueue.h" + +#include "rgw_rados.h" +#include "rgw_rest.h" +#include "rgw_frontend.h" +#include "rgw_request.h" +#include "rgw_process.h" +#include "rgw_loadgen.h" +#include "rgw_client_io.h" + +#define dout_subsys ceph_subsys_rgw + +void RGWProcess::RGWWQ::_dump_queue() +{ + if (!g_conf->subsys.should_gather(ceph_subsys_rgw, 20)) { + return; + } + deque::iterator iter; + if (process->m_req_queue.empty()) { + dout(20) << "RGWWQ: empty" << dendl; + return; + } + dout(20) << "RGWWQ:" << dendl; + for (iter = process->m_req_queue.begin(); + iter != process->m_req_queue.end(); ++iter) { + dout(20) << "req: " << hex << *iter << dec << dendl; + } +} /* RGWProcess::RGWWQ::_dump_queue */ + +int process_request(RGWRados* store, RGWREST* rest, RGWRequest* req, + RGWStreamIO* client_io, OpsLogSocket* olog) +{ + int ret = 0; + + client_io->init(g_ceph_context); + + req->log_init(); + + dout(1) << "====== starting new request req=" << hex << req << dec + << " =====" << dendl; + perfcounter->inc(l_rgw_req); + + RGWEnv& rgw_env = client_io->get_env(); + + RGWUserInfo userinfo; + + struct req_state rstate(g_ceph_context, &rgw_env, &userinfo); + struct req_state *s = &rstate; + + RGWObjectCtx rados_ctx(store, s); + s->obj_ctx = &rados_ctx; + + s->req_id = store->unique_id(req->id); + s->trans_id = store->unique_trans_id(req->id); + s->host_id = store->host_id; + + req->log_format(s, "initializing for trans_id = %s", s->trans_id.c_str()); + + RGWOp* op = NULL; + int init_error = 0; + bool should_log = false; + RGWRESTMgr *mgr; + RGWHandler_REST *handler = rest->get_handler(store, s, client_io, &mgr, + &init_error); + if (init_error != 0) { + abort_early(s, NULL, init_error, NULL); + goto done; + } + dout(10) << "handler=" << typeid(*handler).name() << dendl; + + should_log = mgr->get_logging(); + + req->log_format(s, "getting op %d", s->op); + op = handler->get_op(store); + if (!op) { + abort_early(s, NULL, -ERR_METHOD_NOT_ALLOWED, handler); + goto done; + } + req->op = op; + dout(10) << "op=" << typeid(*op).name() << dendl; + ++ s->op_type = op->get_type(); ++ + req->log(s, "authorizing"); + ret = handler->authorize(); + if (ret < 0) { + dout(10) << "failed to authorize request" << dendl; + abort_early(s, NULL, ret, handler); + goto done; + } + + req->log(s, "normalizing buckets and tenants"); + ret = handler->postauth_init(); + if (ret < 0) { + dout(10) << "failed to run post-auth init" << dendl; + abort_early(s, op, ret, handler); + goto done; + } + + if (s->user->suspended) { + dout(10) << "user is suspended, uid=" << s->user->user_id << dendl; + abort_early(s, op, -ERR_USER_SUSPENDED, handler); + goto done; + } + + req->log(s, "init permissions"); + ret = handler->init_permissions(op); + if (ret < 0) { + abort_early(s, op, ret, handler); + goto done; + } + + /** + * Only some accesses support website mode, and website mode does NOT apply + * if you are using the REST endpoint either (ergo, no authenticated access) + */ + req->log(s, "recalculating target"); + ret = handler->retarget(op, &op); + if (ret < 0) { + abort_early(s, op, ret, handler); + goto done; + } + req->op = op; + + req->log(s, "reading permissions"); + ret = handler->read_permissions(op); + if (ret < 0) { + abort_early(s, op, ret, handler); + goto done; + } + + req->log(s, "init op"); + ret = op->init_processing(); + if (ret < 0) { + abort_early(s, op, ret, handler); + goto done; + } + + req->log(s, "verifying op mask"); + ret = op->verify_op_mask(); + if (ret < 0) { + abort_early(s, op, ret, handler); + goto done; + } + + req->log(s, "verifying op permissions"); + ret = op->verify_permission(); + if (ret < 0) { + if (s->system_request) { + dout(2) << "overriding permissions due to system operation" << dendl; + } else { + abort_early(s, op, ret, handler); + goto done; + } + } + + req->log(s, "verifying op params"); + ret = op->verify_params(); + if (ret < 0) { + abort_early(s, op, ret, handler); + goto done; + } + + req->log(s, "pre-executing"); + op->pre_exec(); + + req->log(s, "executing"); + op->execute(); + + req->log(s, "completing"); + op->complete(); +done: + int r = client_io->complete_request(); + if (r < 0) { + dout(0) << "ERROR: client_io->complete_request() returned " << r << dendl; + } + if (should_log) { + rgw_log_op(store, s, (op ? op->name() : "unknown"), olog); + } + + int http_ret = s->err.http_ret; + int op_ret = 0; + if (op) { + op_ret = op->get_ret(); + } + + req->log_format(s, "op status=%d", op_ret); + req->log_format(s, "http status=%d", http_ret); + + if (handler) + handler->put_op(op); + rest->put_handler(handler); + + dout(1) << "====== req done req=" << hex << req << dec + << " op status=" << op_ret + << " http_status=" << http_ret + << " ======" + << dendl; + + return (ret < 0 ? ret : s->err.ret); +} /* process_request */ diff --cc src/rgw/rgw_rest.cc index c418f358b9d5,a7f306ee806b..fa119947c3a9 --- a/src/rgw/rgw_rest.cc +++ b/src/rgw/rgw_rest.cc @@@ -1001,7 -970,7 +1001,7 @@@ int RGWPutObj_ObjStore::get_data(buffer bufferptr bp(cl); int read_len; /* cio->read() expects int * */ - int r = STREAM_IO(s)->read(bp.c_str(), cl, &read_len); - int r = s->cio->read(bp.c_str(), cl, &read_len, true); ++ int r = STREAM_IO(s)->read(bp.c_str(), cl, &read_len, true); len = read_len; if (r < 0) return r; @@@ -1046,7 -1015,7 +1046,7 @@@ int RGWPutACLs_ObjStore::get_params( return op_ret; } int read_len; - int r = STREAM_IO(s)->read(data, cl, &read_len); - int r = s->cio->read(data, cl, &read_len, s->aws4_auth_needs_complete); ++ int r = STREAM_IO(s)->read(data, cl, &read_len, s->aws4_auth_needs_complete); len = read_len; if (r < 0) return r; @@@ -1071,7 -1039,7 +1071,7 @@@ static int read_all_chunked_input(req_s int read_len = 0, len = 0; do { - int r = STREAM_IO(s)->read(data + len, need_to_read, &read_len); - int r = s->cio->read(data + len, need_to_read, &read_len, s->aws4_auth_needs_complete); ++ int r = STREAM_IO(s)->read(data + len, need_to_read, &read_len, s->aws4_auth_needs_complete); if (r < 0) { free(data); return r; @@@ -1125,7 -1092,7 +1125,7 @@@ int rgw_rest_read_all_input(struct req_ if (!data) { return -ENOMEM; } - int ret = STREAM_IO(s)->read(data, cl, &len); - int ret = s->cio->read(data, cl, &len, s->aws4_auth_needs_complete); ++ int ret = STREAM_IO(s)->read(data, cl, &len, s->aws4_auth_needs_complete); if (ret < 0) { free(data); return ret; @@@ -1230,7 -1198,7 +1230,7 @@@ int RGWDeleteMultiObj_ObjStore::get_par return op_ret; } int read_len; - op_ret = STREAM_IO(s)->read(data, cl, &read_len); - op_ret = s->cio->read(data, cl, &read_len, s->aws4_auth_needs_complete); ++ op_ret = STREAM_IO(s)->read(data, cl, &read_len, s->aws4_auth_needs_complete); len = read_len; if (op_ret < 0) return op_ret; diff --cc src/rgw/rgw_rest_metadata.cc index 13a9aba566e6,3cbb7d77a6dc..1794fbd7b3fd --- a/src/rgw/rgw_rest_metadata.cc +++ b/src/rgw/rgw_rest_metadata.cc @@@ -160,8 -158,15 +160,15 @@@ void RGWOp_Metadata_Put::execute() return; } + if (s->aws4_auth_needs_complete) { + http_ret = do_aws4_auth_completion(); + if (http_ret < 0) { + return; + } + } + frame_metadata_key(s, metadata_key); - + RGWMetadataHandler::sync_type_t sync_type = RGWMetadataHandler::APPLY_ALWAYS; bool mode_exists = false; diff --cc src/rgw/rgw_rest_s3.cc index 41118414c813,72afee8800c1..105ad8711b8b --- a/src/rgw/rgw_rest_s3.cc +++ b/src/rgw/rgw_rest_s3.cc @@@ -1836,12 -1725,24 +1864,26 @@@ void RGWGetACLs_ObjStore_S3::send_respo end_header(s, this, "application/xml"); dump_start(s); rgw_flush_formatter(s, s->formatter); - s->cio->write(acls.c_str(), acls.size()); + STREAM_IO(s)->write(acls.c_str(), acls.size()); } + int RGWPutACLs_ObjStore_S3::get_params() + { + int ret = RGWPutACLs_ObjStore::get_params(); + if (ret < 0) + s->aws4_auth_needs_complete = false; + if (s->aws4_auth_needs_complete) { + int ret_auth = do_aws4_auth_completion(); + if (ret_auth < 0) { + return ret_auth; + } + } + return ret; + } + -int RGWPutACLs_ObjStore_S3::get_policy_from_state(RGWRados *store, struct req_state *s, stringstream& ss) +int RGWPutACLs_ObjStore_S3::get_policy_from_state(RGWRados *store, + struct req_state *s, + stringstream& ss) { RGWAccessControlPolicy_S3 s3policy(s->cct); @@@ -1910,7 -1810,7 +1952,7 @@@ int RGWPutCORS_ObjStore_S3::get_params( goto done_err; } int read_len; - r = STREAM_IO(s)->read(data, cl, &read_len); - r = s->cio->read(data, cl, &read_len, s->aws4_auth_needs_complete); ++ r = STREAM_IO(s)->read(data, cl, &read_len, s->aws4_auth_needs_complete); len = read_len; if (r < 0) goto done_err; @@@ -2780,24 -2737,601 +2857,601 @@@ int RGW_Auth_S3::authorize(RGWRados *st } if (!s->http_auth || !(*s->http_auth)) { - auth_id = s->info.args.get("AWSAccessKeyId"); + + /* AWS4 */ + + string algorithm = s->info.args.get("X-Amz-Algorithm"); + if (algorithm.size()) { + if (algorithm != "AWS4-HMAC-SHA256") { + return -EPERM; + } + return authorize_v4(store, s); + } + + /* AWS2 */ + + string auth_id = s->info.args.get("AWSAccessKeyId"); if (auth_id.size()) { - auth_sign = s->info.args.get("Signature"); + return authorize_v2(store, s); + } - string date = s->info.args.get("Expires"); - time_t exp = atoll(date.c_str()); - if (now >= exp) - return -EPERM; + /* anonymous access */ - qsr = true; - } else { - /* anonymous access */ - init_anon_user(s); - return 0; + init_anon_user(s); + return 0; + + } else { + + /* AWS4 */ + + if (!strncmp(s->http_auth, "AWS4-HMAC-SHA256", 16)) { + return authorize_v4(store, s); + } + + /* AWS2 */ + + if (!strncmp(s->http_auth, "AWS ", 4)) { + return authorize_v2(store, s); + } + + } + + return -EINVAL; + } + + int RGW_Auth_S3::authorize_aws4_auth_complete(RGWRados *store, struct req_state *s) + { + return authorize_v4_complete(store, s, "", false); + } + + int RGW_Auth_S3::authorize_v4_complete(RGWRados *store, struct req_state *s, const string& request_payload, bool unsigned_payload) + { + size_t pos; + + /* craft canonical request */ + + string canonical_req; + string canonical_req_hash; + + rgw_create_s3_v4_canonical_request(s, s->aws4_auth->canonical_uri, s->aws4_auth->canonical_qs, + s->aws4_auth->canonical_hdrs, s->aws4_auth->signed_hdrs, request_payload, unsigned_payload, + canonical_req, canonical_req_hash); + + /* Validate x-amz-sha256 */ + + if (s->aws4_auth_needs_complete) { + const char *expected_request_payload_hash = s->info.env->get("HTTP_X_AMZ_CONTENT_SHA256"); + if (expected_request_payload_hash && + s->aws4_auth->payload_hash.compare(expected_request_payload_hash) != 0) { + ldout(s->cct, 10) << "ERROR: x-amz-content-sha256 does not match" << dendl; + return -ERR_AMZ_CONTENT_SHA256_MISMATCH; + } + } + + /* + * create a string to sign + * + * http://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html + */ + + string string_to_sign; + + rgw_create_s3_v4_string_to_sign(s->cct, "AWS4-HMAC-SHA256", s->aws4_auth->date, s->aws4_auth->credential_scope, + canonical_req_hash, string_to_sign); + + /* + * calculate the AWS signature + * + * http://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html + */ + + string cs_aux = s->aws4_auth->credential_scope; + + string date_cs = cs_aux; + pos = date_cs.find("/"); + date_cs = date_cs.substr(0, pos); + cs_aux = cs_aux.substr(pos + 1, cs_aux.length()); + + string region_cs = cs_aux; + pos = region_cs.find("/"); + region_cs = region_cs.substr(0, pos); + cs_aux = cs_aux.substr(pos + 1, cs_aux.length()); + + string service_cs = cs_aux; + pos = service_cs.find("/"); + service_cs = service_cs.substr(0, pos); + + int err = rgw_calculate_s3_v4_aws_signature(s, s->aws4_auth->access_key_id, date_cs, + region_cs, service_cs, string_to_sign, s->aws4_auth->new_signature); + + ldout(s->cct, 10) << "----------------------------- Verifying signatures" << dendl; + ldout(s->cct, 10) << "Signature = " << s->aws4_auth->signature << dendl; + ldout(s->cct, 10) << "New Signature = " << s->aws4_auth->new_signature << dendl; + ldout(s->cct, 10) << "-----------------------------" << dendl; + + if (err) { + return err; + } + + return 0; + + } + + static inline bool is_base64_for_content_md5(unsigned char c) { + return (isalnum(c) || isspace(c) || (c == '+') || (c == '/') || (c == '=')); + } + + static bool char_needs_aws4_escaping(char c) + { + if ((c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9')) { + return false; + } + + switch (c) { + case '-': + case '_': + case '.': + case '~': + return false; + } + return true; + } + + static void aws4_uri_encode(const string& src, string& dst) + { + const char *p = src.c_str(); + for (unsigned i = 0; i < src.size(); i++, p++) { + if (char_needs_aws4_escaping(*p)) { + rgw_uri_escape_char(*p, dst); + continue; + } + + dst.append(p, 1); + } + } + + /* + * handle v4 signatures (rados auth only) + */ + int RGW_Auth_S3::authorize_v4(RGWRados *store, struct req_state *s) + { + string::size_type pos; + bool using_qs; + + time_t now, now_req=0; + time(&now); + + /* v4 requires rados auth */ + if (!store->ctx()->_conf->rgw_s3_auth_use_rados) { + return -EPERM; + } + + string algorithm = "AWS4-HMAC-SHA256"; + + s->aws4_auth = new rgw_aws4_auth; + + if ((!s->http_auth) || !(*s->http_auth)) { + + /* auth ships with req params ... */ + + /* look for required params */ + + using_qs = true; + s->aws4_auth->credential = s->info.args.get("X-Amz-Credential"); + if (s->aws4_auth->credential.size() == 0) { + return -EPERM; + } + + s->aws4_auth->date = s->info.args.get("X-Amz-Date"); + struct tm date_t; + if (!parse_iso8601(s->aws4_auth->date.c_str(), &date_t, false)) + return -EPERM; + + s->aws4_auth->expires = s->info.args.get("X-Amz-Expires"); + if (s->aws4_auth->expires.size() != 0) { + /* X-Amz-Expires provides the time period, in seconds, for which + the generated presigned URL is valid. The minimum value + you can set is 1, and the maximum is 604800 (seven days) */ + time_t exp = atoll(s->aws4_auth->expires.c_str()); + if ((exp < 1) || (exp > 604800)) { + dout(10) << "NOTICE: exp out of range, exp = " << exp << dendl; + return -EPERM; + } + /* handle expiration in epoch time */ + now_req = mktime(&date_t); + if (now >= now_req + exp) { + dout(10) << "NOTICE: now = " << now << ", now_req = " << now_req << ", exp = " << exp << dendl; + return -EPERM; + } + } + + if ( (now_req < now - RGW_AUTH_GRACE_MINS * 60) || + (now_req > now + RGW_AUTH_GRACE_MINS * 60) ) { + dout(10) << "NOTICE: request time skew too big." << dendl; + dout(10) << "now_req = " << now_req << " now = " << now << "; now - RGW_AUTH_GRACE_MINS=" << now - RGW_AUTH_GRACE_MINS * 60 << "; now + RGW_AUTH_GRACE_MINS=" << now + RGW_AUTH_GRACE_MINS * 60 << dendl; + return -ERR_REQUEST_TIME_SKEWED; } + + s->aws4_auth->signedheaders = s->info.args.get("X-Amz-SignedHeaders"); + if (s->aws4_auth->signedheaders.size() == 0) { + return -EPERM; + } + + s->aws4_auth->signature = s->info.args.get("X-Amz-Signature"); + if (s->aws4_auth->signature.size() == 0) { + return -EPERM; + } + } else { - if (strncmp(s->http_auth, "AWS ", 4)) + + /* auth ships in headers ... */ + + /* ------------------------- handle Credential header */ + + using_qs = false; + s->aws4_auth->credential = s->http_auth; + + s->aws4_auth->credential = s->aws4_auth->credential.substr(17, s->aws4_auth->credential.length()); + + pos = s->aws4_auth->credential.find("Credential"); + if (pos == std::string::npos) { + return -EINVAL; + } + + s->aws4_auth->credential = s->aws4_auth->credential.substr(pos, s->aws4_auth->credential.find(",")); + + s->aws4_auth->credential = s->aws4_auth->credential.substr(pos + 1, s->aws4_auth->credential.length()); + + pos = s->aws4_auth->credential.find("="); + + s->aws4_auth->credential = s->aws4_auth->credential.substr(pos + 1, s->aws4_auth->credential.length()); + + /* ------------------------- handle SignedHeaders header */ + + s->aws4_auth->signedheaders = s->http_auth; + + s->aws4_auth->signedheaders = s->aws4_auth->signedheaders.substr(17, s->aws4_auth->signedheaders.length()); + + pos = s->aws4_auth->signedheaders.find("SignedHeaders"); + if (pos == std::string::npos) { + return -EINVAL; + } + + s->aws4_auth->signedheaders = s->aws4_auth->signedheaders.substr(pos, s->aws4_auth->signedheaders.length()); + + pos = s->aws4_auth->signedheaders.find(","); + if (pos == std::string::npos) { + return -EINVAL; + } + + s->aws4_auth->signedheaders = s->aws4_auth->signedheaders.substr(0, pos); + + pos = s->aws4_auth->signedheaders.find("="); + if (pos == std::string::npos) { return -EINVAL; + } + + s->aws4_auth->signedheaders = s->aws4_auth->signedheaders.substr(pos + 1, s->aws4_auth->signedheaders.length()); + + /* host;user-agent;x-amz-content-sha256;x-amz-date */ + dout(10) << "v4 signedheaders format = " << s->aws4_auth->signedheaders << dendl; + + /* ------------------------- handle Signature header */ + + s->aws4_auth->signature = s->http_auth; + + s->aws4_auth->signature = s->aws4_auth->signature.substr(17, s->aws4_auth->signature.length()); + + pos = s->aws4_auth->signature.find("Signature"); + if (pos == std::string::npos) { + return -EINVAL; + } + + s->aws4_auth->signature = s->aws4_auth->signature.substr(pos, s->aws4_auth->signature.length()); + + pos = s->aws4_auth->signature.find("="); + if (pos == std::string::npos) { + return -EINVAL; + } + + s->aws4_auth->signature = s->aws4_auth->signature.substr(pos + 1, s->aws4_auth->signature.length()); + + /* sig hex str */ + dout(10) << "v4 signature format = " << s->aws4_auth->signature << dendl; + + /* ------------------------- handle x-amz-date header */ + + /* grab date */ + + const char *d = s->info.env->get("HTTP_X_AMZ_DATE"); + struct tm t; + if (!parse_iso8601(d, &t, false)) { + dout(10) << "error reading date via http_x_amz_date" << dendl; + return -EACCES; + } + s->aws4_auth->date = d; + } + + /* AKIAIVKTAZLOCF43WNQD/AAAAMMDD/region/host/aws4_request */ + dout(10) << "v4 credential format = " << s->aws4_auth->credential << dendl; + + if (std::count(s->aws4_auth->credential.begin(), s->aws4_auth->credential.end(), '/') != 4) { + return -EINVAL; + } + + /* credential must end with 'aws4_request' */ + if (s->aws4_auth->credential.find("aws4_request") == std::string::npos) { + return -EINVAL; + } + + /* grab access key id */ + + pos = s->aws4_auth->credential.find("/"); + s->aws4_auth->access_key_id = s->aws4_auth->credential.substr(0, pos); + + dout(10) << "access key id = " << s->aws4_auth->access_key_id << dendl; + + /* grab credential scope */ + + s->aws4_auth->credential_scope = s->aws4_auth->credential.substr(pos + 1, s->aws4_auth->credential.length()); + + dout(10) << "credential scope = " << s->aws4_auth->credential_scope << dendl; + + /* grab user information */ + - if (rgw_get_user_info_by_access_key(store, s->aws4_auth->access_key_id, s->user) < 0) { ++ if (rgw_get_user_info_by_access_key(store, s->aws4_auth->access_key_id, *s->user) < 0) { + dout(10) << "error reading user info, uid=" << s->aws4_auth->access_key_id + << " can't authenticate" << dendl; + return -ERR_INVALID_ACCESS_KEY; + } + + /* + * create a canonical request + * + * http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html + */ + + /* craft canonical uri */ + + /* here code should normalize via rfc3986 but S3 does **NOT** do path normalization + * that SigV4 typically does. this code follows the same approach that boto library + * see auth.py:canonical_uri(...) */ + + s->aws4_auth->canonical_uri = s->info.request_uri; + + if (s->aws4_auth->canonical_uri.empty()) { + s->aws4_auth->canonical_uri = "/"; + } + + /* craft canonical query string */ + + s->aws4_auth->canonical_qs = s->info.request_params; + + if (!s->aws4_auth->canonical_qs.empty()) { + + /* handle case when query string exists. Step 3 in + * http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html */ + + map canonical_qs_map; + istringstream cqs(s->aws4_auth->canonical_qs); + string keyval; + + while (getline(cqs, keyval, '&')) { + string key, val; + istringstream kv(keyval); + getline(kv, key, '='); + getline(kv, val, '='); + if (!using_qs || key != "X-Amz-Signature") { + string encoded_key; + string encoded_val; + if (key != "X-Amz-Credential") { + aws4_uri_encode(key, encoded_key); + aws4_uri_encode(val, encoded_val); + } else { + encoded_key = key; + encoded_val = val; + } + canonical_qs_map[encoded_key] = encoded_val; + } + } + + s->aws4_auth->canonical_qs = ""; + + map::iterator last = canonical_qs_map.end(); + --last; + + for (map::iterator it = canonical_qs_map.begin(); + it != canonical_qs_map.end(); ++it) { + s->aws4_auth->canonical_qs.append(it->first + "=" + it->second); + if (it != last) { + s->aws4_auth->canonical_qs.append("&"); + } + } + + } + + /* craft canonical headers */ + + map canonical_hdrs_map; + istringstream sh(s->aws4_auth->signedheaders); + string token; + string port = s->info.env->get("SERVER_PORT"); + + while (getline(sh, token, ';')) { + string token_env = "HTTP_" + token; + transform(token_env.begin(), token_env.end(), token_env.begin(), ::toupper); + replace(token_env.begin(), token_env.end(), '-', '_'); + if (token_env == "HTTP_CONTENT_LENGTH") { + token_env = "CONTENT_LENGTH"; + } + if (token_env == "HTTP_CONTENT_TYPE") { + token_env = "CONTENT_TYPE"; + } + const char *t = s->info.env->get(token_env.c_str()); + if (!t) { + dout(10) << "warning env var not available" << dendl; + continue; + } + if (token_env == "HTTP_CONTENT_MD5") { + for (const char *p = t; *p; p++) { + if (!is_base64_for_content_md5(*p)) { + dout(0) << "NOTICE: bad content-md5 provided (not base64), aborting request p=" << *p << " " << (int)*p << dendl; + return -EPERM; + } + } + } + string token_value = string(t); + if (using_qs && (token == "host")) + token_value = token_value + ":" + port; + canonical_hdrs_map[token] = rgw_trim_whitespace(token_value); + } + + for (map::iterator it = canonical_hdrs_map.begin(); + it != canonical_hdrs_map.end(); ++it) { + s->aws4_auth->canonical_hdrs.append(it->first + ":" + it->second + "\n"); + } + + dout(10) << "canonical headers format = " << s->aws4_auth->canonical_hdrs << dendl; + + /* craft signed headers */ + + s->aws4_auth->signed_hdrs = s->aws4_auth->signedheaders; + + /* handle request payload */ + + /* from rfc2616 - 4.3 Message Body + * + * "The presence of a message-body in a request is signaled by the inclusion of a + * Content-Length or Transfer-Encoding header field in the request's message-headers." + */ + + s->aws4_auth->payload_hash = ""; + + string request_payload; + + bool unsigned_payload = false; + if (using_qs) { + unsigned_payload = true; + } + + if (using_qs || ((s->content_length == 0) && s->info.env->get("HTTP_TRANSFER_ENCODING") == NULL)) { + + /* requests lacking of body are authenticated now */ + + /* complete aws4 auth */ + + int err = authorize_v4_complete(store, s, request_payload, unsigned_payload); + if (err) { + return err; + } + + /* verify signature */ + + if (s->aws4_auth->signature != s->aws4_auth->new_signature) { + return -ERR_SIGNATURE_NO_MATCH; + } + + /* authorization ok */ + + dout(10) << "v4 auth ok" << dendl; + + /* aws4 auth completed */ + + s->aws4_auth_needs_complete = false; + + } else { + + /* aws4 auth not completed... delay aws4 auth */ + + dout(10) << "body content detected... delaying v4 auth" << dendl; + + switch (s->op_type) + { + case RGW_OP_CREATE_BUCKET: + case RGW_OP_PUT_OBJ: + case RGW_OP_PUT_ACLS: + case RGW_OP_PUT_CORS: + case RGW_OP_COMPLETE_MULTIPART: + case RGW_OP_SET_BUCKET_VERSIONING: + case RGW_OP_DELETE_MULTI_OBJ: + case RGW_OP_ADMIN_SET_METADATA: + break; + default: + dout(10) << "ERROR: AWS4 completion for this operation NOT IMPLEMENTED" << dendl; + return -ERR_NOT_IMPLEMENTED; + } + + s->aws4_auth_needs_complete = true; + + } + - map::iterator iter = s->user.access_keys.find(s->aws4_auth->access_key_id); - if (iter == s->user.access_keys.end()) { ++ map::iterator iter = s->user->access_keys.find(s->aws4_auth->access_key_id); ++ if (iter == s->user->access_keys.end()) { + dout(0) << "ERROR: access key not encoded in user info" << dendl; + return -EPERM; + } + + RGWAccessKey& k = iter->second; + + if (!k.subuser.empty()) { - map::iterator uiter = s->user.subusers.find(k.subuser); - if (uiter == s->user.subusers.end()) { ++ map::iterator uiter = s->user->subusers.find(k.subuser); ++ if (uiter == s->user->subusers.end()) { + dout(0) << "NOTICE: could not find subuser: " << k.subuser << dendl; + return -EPERM; + } + RGWSubUser& subuser = uiter->second; + s->perm_mask = subuser.perm_mask; + } else { + s->perm_mask = RGW_PERM_FULL_CONTROL; + } + - if (s->user.system) { ++ if (s->user->system) { + s->system_request = true; + dout(20) << "system request" << dendl; + s->info.args.set_system(); + string euid = s->info.args.get(RGW_SYS_PARAM_PREFIX "uid"); + rgw_user effective_uid(euid); + RGWUserInfo effective_user; + if (!effective_uid.empty()) { + int ret = rgw_get_user_info_by_uid(store, effective_uid, effective_user); + if (ret < 0) { + ldout(s->cct, 0) << "User lookup failed!" << dendl; + return -ENOENT; + } - s->user = effective_user; ++ *(s->user) = effective_user; + } + } + + // populate the owner info - s->owner.set_id(s->user.user_id); - s->owner.set_name(s->user.display_name); ++ s->owner.set_id(s->user->user_id); ++ s->owner.set_name(s->user->display_name); + + return 0; + } + + /* + * handle v2 signatures + */ + int RGW_Auth_S3::authorize_v2(RGWRados *store, struct req_state *s) + { + bool qsr = false; + string auth_id; + string auth_sign; + + time_t now; + time(&now); + + if (!s->http_auth || !(*s->http_auth)) { + auth_id = s->info.args.get("AWSAccessKeyId"); + auth_sign = s->info.args.get("Signature"); + string date = s->info.args.get("Expires"); + time_t exp = atoll(date.c_str()); + if (now >= exp) + return -EPERM; + qsr = true; + } else { string auth_str(s->http_auth + 4); int pos = auth_str.rfind(':'); if (pos < 0) diff --cc src/rgw/rgw_rest_s3.h index a97b82fe1cdd,5417de8d7041..7c70ec1481a9 --- a/src/rgw/rgw_rest_s3.h +++ b/src/rgw/rgw_rest_s3.h @@@ -390,12 -390,19 +394,19 @@@ public class RGW_Auth_S3 { public: static int authorize(RGWRados *store, struct req_state *s); + static int authorize_aws4_auth_complete(RGWRados *store, struct req_state *s); + private: + static int authorize_v2(RGWRados *store, struct req_state *s); + static int authorize_v4(RGWRados *store, struct req_state *s); + static int authorize_v4_complete(RGWRados *store, struct req_state *s, + const string& request_payload, bool unsigned_payload); + }; -class RGWHandler_Auth_S3 : public RGWHandler_ObjStore { +class RGWHandler_Auth_S3 : public RGWHandler_REST { friend class RGWRESTMgr_S3; public: - RGWHandler_Auth_S3() : RGWHandler_ObjStore() {} + RGWHandler_Auth_S3() : RGWHandler_REST() {} virtual ~RGWHandler_Auth_S3() {} virtual int validate_bucket_name(const string& bucket) {