// 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
return true;
}
- request_payload_hash = s->cio->grab_aws4_sha256_hash();
+
+ /*
+ * 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) {
- map<string, RGWAccessKey>::iterator iter = s->user.access_keys.find(access_key_id);
- if (iter == s->user.access_keys.end()) {
++ 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<string, RGWAccessKey>::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;
+ }
#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<string, string>& meta_map, const char *request_uri, map<string, string>& 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<string, string>& meta_map,
+ const char *request_uri,
+ map<string, string>& 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
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)
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);
+ }
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;
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;
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<string, string> 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<string, string> 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<string, bufferlist> 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<string, bufferlist> 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 */
#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"
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; }
--- /dev/null
+// -*- 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<RGWRequest *>::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 */
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;
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;
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;
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;
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;
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;
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_policy_from_state(RGWRados *store, struct req_state *s, stringstream& ss)
+ 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)
{
RGWAccessControlPolicy_S3 s3policy(s->cct);
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;
}
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;
- if (rgw_get_user_info_by_access_key(store, s->aws4_auth->access_key_id, s->user) < 0) {
+ }
+
+ 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 */
+
- map<string, RGWAccessKey>::iterator iter = s->user.access_keys.find(s->aws4_auth->access_key_id);
- if (iter == s->user.access_keys.end()) {
++ 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<string, string> 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<string, string>::iterator last = canonical_qs_map.end();
+ --last;
+
+ for (map<string, string>::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<string, string> 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<string, string>::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<string, RGWSubUser>::iterator uiter = s->user.subusers.find(k.subuser);
- if (uiter == s->user.subusers.end()) {
++ map<string, RGWAccessKey>::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()) {
- if (s->user.system) {
++ map<string, RGWSubUser>::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;
+ }
+
- s->user = effective_user;
++ 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->owner.set_id(s->user.user_id);
- s->owner.set_name(s->user.display_name);
++ *(s->user) = effective_user;
+ }
+ }
+
+ // populate the owner info
++ 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)
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) {